From 0abb99b884700bd892f7a56a7ae722b58e2e52af Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 23:16:13 +0200 Subject: [PATCH 001/238] fix whitespacing in generated code --- .../PixelOperations{TPixel}.Generated.cs | 140 +++++++++--------- .../PixelOperations{TPixel}.Generated.tt | 29 ++-- 2 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index e8908fe05e..3ea4007d22 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -1,4 +1,13 @@ -// Copyright (c) Six Labors and contributors. + + + + + + + + + +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // @@ -10,8 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { - - /// + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -19,7 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -34,8 +42,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgba64(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -47,8 +55,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -70,20 +78,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba64Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToRgba64(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -91,7 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -106,8 +114,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgb48(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -119,8 +127,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -142,20 +150,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb48Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToRgb48(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -163,7 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -178,8 +186,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgba32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -191,8 +199,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -214,20 +222,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToRgba32(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -235,7 +243,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -250,8 +258,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromBgra32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -263,8 +271,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -286,20 +294,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgra32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToBgra32(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -307,7 +315,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -322,8 +330,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgba32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -335,8 +343,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -358,20 +366,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToRgb24(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -379,7 +387,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -394,8 +402,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromRgba32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -407,8 +415,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -430,20 +438,20 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgr24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToBgr24(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - /// + + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -451,7 +459,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -466,8 +474,8 @@ namespace SixLabors.ImageSharp.PixelFormats dp.PackFromArgb32(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -479,8 +487,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - - /// + + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -502,19 +510,17 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToArgb32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.ToArgb32(sourceColors, MemoryMarshal.Cast(destBytes), count); } - - } - + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index 5c762c7df1..dbd30560ea 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -14,8 +14,7 @@ void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) { #> - - /// + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// /// The source of data. @@ -23,7 +22,7 @@ /// The number of pixels to convert. internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); @@ -38,8 +37,8 @@ dp.PackFrom<#=tempPixelType#>(temp); } } - - /// + + /// /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// @@ -51,14 +50,13 @@ { this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); } - <# +<# } void GenerateToDestFormatMethods(string pixelType) { #> - - /// + /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// Bulk version of . /// @@ -80,19 +78,19 @@ } } - /// + /// /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void To<#=pixelType#>Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) { this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast>(destBytes), count); } - <# +<# } #> @@ -107,8 +105,8 @@ namespace SixLabors.ImageSharp.PixelFormats using System.Runtime.InteropServices; public partial class PixelOperations - { - <# + {<# + GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba64"); @@ -129,8 +127,5 @@ namespace SixLabors.ImageSharp.PixelFormats GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Argb32"); - #> - - } - + #> } } \ No newline at end of file From 9720fea2da3eecf14e0f2327728f47309e830df0 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 15:19:11 +0200 Subject: [PATCH 002/238] #718: add pixel types Gray8 and Gray16 --- src/ImageSharp/PixelFormats/Gray16.cs | 270 ++++++++++++++++++ src/ImageSharp/PixelFormats/Gray8.cs | 265 +++++++++++++++++ .../PixelFormats/Gray8Tests.cs | 211 ++++++++++++++ 3 files changed, 746 insertions(+) create mode 100644 src/ImageSharp/PixelFormats/Gray16.cs create mode 100644 src/ImageSharp/PixelFormats/Gray8.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs new file mode 100644 index 0000000000..a7e50e3667 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -0,0 +1,270 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 16 bit normalized gray values. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + public struct Gray16 : IPixel, IPackedVector + { + /// + /// RX as in ITU-R recommendation 709 to match libpng + /// + private const float Rx = .2126F; + + /// + /// GX as in ITU-R recommendation 709 to match libpng + /// + private const float Gx = .7152F; + + /// + /// BX as in ITU-R recommendation 709 to match libpng + /// + private const float Bx = .0722F; + + /// + /// Initializes a new instance of the struct. + /// + /// The gray component + public Gray16(byte gray) + { + this.PackedValue = gray; + } + + /// + public ushort PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// + /// The on the left side of the operand. + /// + /// + /// The on the right side of the operand. + /// + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Gray16 left, Gray16 right) + { + return left.PackedValue == right.PackedValue; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Gray16 left, Gray16 right) + { + return left.PackedValue != right.PackedValue; + } + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromScaledVector4(Vector4 vector) + { + this.PackFromVector4(vector); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToScaledVector4() + { + var scaledGray = this.PackedValue / 65535f; // ushort.Max as float + return new Vector4(scaledGray, scaledGray, scaledGray, 1.0f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromVector4(Vector4 vector) + { + this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.PackedValue, this.PackedValue, this.PackedValue, 1.0f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba32(Rgba32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromArgb32(Argb32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromBgra32(Bgra32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb24(ref Rgb24 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba32(ref Rgba32 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToArgb32(ref Argb32 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgr24(ref Bgr24 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgra32(ref Bgra32 dest) + { + var scaledValue = this.PackedAsByte(); + + dest.R = scaledValue; + dest.G = scaledValue; + dest.B = scaledValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgb48(Rgb48 source) => + this.PackedValue = Pack(source.R, source.G, source.B); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb48(ref Rgb48 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => + this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + /// Compares an object with the packed vector. + /// + /// The object to compare. + /// True if the object is equal to the packed vector. + public override bool Equals(object obj) + { + return obj is Gray16 other && this.Equals(other); + } + + /// + /// Compares another packed vector with the packed vector. + /// + /// The Gray8 packed vector to compare. + /// True if the packed vectors are equal. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Gray16 other) + { + return this.PackedValue == other.PackedValue; + } + + /// + /// Gets a string representation of the packed vector. + /// + /// A string representation of the packed vector. + public override string ToString() + { + return (this.PackedValue / 65535f).ToString(); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + /// Packs a into a byte. + /// + /// Red value of the color to pack. + /// Green value of the color to pack. + /// Blue value of the color to pack. + /// The containing the packed value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(float r, float g, float b) + { + float sum = r + g + b; + float val = (r * Rx) + (g * Gx) + (b * Bx); + return (ushort)Math.Round(val * 65535f / sum); // TODO: if this is correct, Rx, Gx, Bx consts could be scaled by 65535f directly! + } + + /// + /// Packs the into a byte. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private byte PackedAsByte() + { + return (byte)(this.PackedValue >> 8); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs new file mode 100644 index 0000000000..db05395431 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -0,0 +1,265 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 8 bit normalized gray values. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + public struct Gray8 : IPixel, IPackedVector + { + /// + /// RX as in ITU-R recommendation 709 to match libpng + /// + private const float Rx = .2126F; + + /// + /// GX as in ITU-R recommendation 709 to match libpng + /// + private const float Gx = .7152F; + + /// + /// BX as in ITU-R recommendation 709 to match libpng + /// + private const float Bx = .0722F; + + /// + /// Initializes a new instance of the struct. + /// + /// The gray component + public Gray8(byte gray) + { + this.PackedValue = gray; + } + + /// + public byte PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// + /// The on the left side of the operand. + /// + /// + /// The on the right side of the operand. + /// + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Gray8 left, Gray8 right) + { + return left.PackedValue == right.PackedValue; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Gray8 left, Gray8 right) + { + return left.PackedValue != right.PackedValue; + } + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromScaledVector4(Vector4 vector) + { + this.PackFromVector4(vector); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToScaledVector4() + { + var scaledGray = this.PackedValue / 255f; + return new Vector4(scaledGray, scaledGray, scaledGray, 1.0f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromVector4(Vector4 vector) + { + this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.PackedValue, this.PackedValue, this.PackedValue, 1.0f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba32(Rgba32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromArgb32(Argb32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromBgra32(Bgra32 source) + { + this.PackedValue = Pack(source.R, source.G, source.B); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb24(ref Rgb24 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToArgb32(ref Argb32 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgr24(ref Bgr24 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToBgra32(ref Bgra32 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + dest.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgb48(Rgb48 source) => + this.PackedValue = Pack(source.R, source.G, source.B); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgb48(ref Rgb48 dest) + { + ushort gray = (ushort)(this.PackedValue * 255); + dest.R = gray; + dest.G = gray; + dest.B = gray; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromRgba64(Rgba64 source) => + this.PackFromScaledVector4(source.ToScaledVector4()); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackedValue = (byte)(source.PackedValue / 255); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackedValue = this.PackedValue; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackedValue = (ushort)(this.PackedValue * 255); + + /// + /// Compares an object with the packed vector. + /// + /// The object to compare. + /// True if the object is equal to the packed vector. + public override bool Equals(object obj) + { + return obj is Gray8 other && this.Equals(other); + } + + /// + /// Compares another packed vector with the packed vector. + /// + /// The Gray8 packed vector to compare. + /// True if the packed vectors are equal. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Gray8 other) + { + return this.PackedValue == other.PackedValue; + } + + /// + /// Gets a string representation of the packed vector. + /// + /// A string representation of the packed vector. + public override string ToString() + { + return (this.PackedValue / 255F).ToString(); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + /// Packs a into a byte. + /// + /// Red value of the color to pack. + /// Green value of the color to pack. + /// Blue value of the color to pack. + /// The containing the packed value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte Pack(float r, float g, float b) + { + float sum = r + g + b; + float val = (r * Rx) + (g * Gx) + (b * Bx); + return (byte)Math.Round(val * 255 / sum); // TODO: if this is correct, Rx, Gx, Bx consts could be scaled by 255 directly! + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs new file mode 100644 index 0000000000..c4ce7339da --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -0,0 +1,211 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Gray8Tests + { + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(10)] + [InlineData(42)] + public void Gray8_PackedValue_EqualsInput(byte input) + { + Assert.Equal(input, new Gray8(input).PackedValue); + } + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToVector4(byte input) + { + // arrange + var gray = new Gray8(input); + + // act + var actual = gray.ToVector4(); + + // assert + Assert.Equal(input, actual.X); + Assert.Equal(input, actual.Y); + Assert.Equal(input, actual.Z); + Assert.Equal(1, actual.W); + } + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToScaledVector4(byte input) + { + // arrange + var gray = new Gray8(input); + + // act + var actual = gray.ToScaledVector4(); + + // assert + float scaledInput = input / 255f; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Fact] + public void Gray8_PackFromScaledVector4() + { + // arrange + Gray8 gray = default; + int expected = 128; + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + byte actual = gray.PackedValue; + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToRgb24() + { + // arrange + Rgb24 actual = default; + Gray8 gray = default; + var expected = new Rgb24(0, 0, 0); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgb24(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToRgba32() + { + // arrange + Rgba32 actual = default; + Gray8 gray = default; + var expected = new Rgba32(0, 0, 0, 128); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgba32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToBgr24() + { + // arrange + Bgr24 actual = default; + Gray8 gray = default; + var expected = new Bgr24(128, 128, 128); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToBgr24(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToBgra32() + { + // arrange + Bgra32 actual = default; + Gray8 gray = default; + var expected = new Bgra32(128,128,128); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToBgra32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToArgb32() + { + // arrange + Gray8 gray = default; + Argb32 actual = default; + var expected = new Argb32(128, 128, 128); + Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToArgb32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromScaledVector4_ToRgba64() + { + // arrange + Gray8 gray = default; + Rgba64 actual = default; + var expected = new Rgba64(65535, 65535, 65535, 65535); + Vector4 scaled = new Gray8(255).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromRgb48_ToRgb48() + { + // arrange + var gray = default(Gray8); + var actual = default(Rgb48); + var expected = new Rgb48(0, 0, 0); + + // act + gray.PackFromRgb48(expected); + gray.ToRgb48(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray8_PackFromRgba64_ToRgba64() + { + // arrange + var gray = default(Gray8); + var actual = default(Rgba64); + var expected = new Rgba64(0, 0, 0, 65535); + + // act + gray.PackFromRgba64(expected); + gray.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } + } +} From 0354f32c447c7a68d8509d2e9b97af8bbda34f45 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 23:23:39 +0200 Subject: [PATCH 003/238] #718: fix merge conflicts, adapt changes from PR #727 to t4 script --- .../PixelOperations{TPixel}.Generated.cs | 72 +++++++++++++++++++ .../PixelOperations{TPixel}.Generated.tt | 5 +- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index 3ea4007d22..50398eeb25 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -522,5 +522,77 @@ namespace SixLabors.ImageSharp.PixelFormats { this.ToArgb32(sourceColors, MemoryMarshal.Cast(destBytes), count); } + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(source); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors.Black; + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromGray8(temp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); + } + + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Bulk version of . + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); + sp.ToGray8(ref dp); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToGray8Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + { + this.ToGray8(sourceColors, MemoryMarshal.Cast(destBytes), count); + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index dbd30560ea..b4b577e3ab 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -127,5 +127,8 @@ namespace SixLabors.ImageSharp.PixelFormats GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Argb32"); - #> } + + GeneratePackFromMethods("Gray8", "Gray8", "temp = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Gray8"); +#> } } \ No newline at end of file From 904fcd5c532ceb6c0c72f8b4ed84f5fe5da4ea7c Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 19:19:58 +0200 Subject: [PATCH 004/238] #718: fix Gray8Tests --- tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index c4ce7339da..64ad0bff60 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange Rgb24 actual = default; Gray8 gray = default; - var expected = new Rgb24(0, 0, 0); + var expected = new Rgb24(128, 128, 128); Vector4 scaled = new Gray8(128).ToScaledVector4(); // act @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange Rgba32 actual = default; Gray8 gray = default; - var expected = new Rgba32(0, 0, 0, 128); + var expected = new Rgba32(128, 128, 128, 255); Vector4 scaled = new Gray8(128).ToScaledVector4(); // act From 58a5232e723c0f573ec699934b15e94ec7e1794f Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 22:13:58 +0200 Subject: [PATCH 005/238] #718: extend IPixel interface and implement it everywhere, ... AND add unit tests AND fix Gray16 implementation (constructor takes ushort, not byte) AND fix Gray8 and Gray16 Pack (do not scale by sum) --- src/ImageSharp/PixelFormats/Alpha8.cs | 16 ++ src/ImageSharp/PixelFormats/Argb32.cs | 30 +++ src/ImageSharp/PixelFormats/Bgr24.cs | 27 +++ src/ImageSharp/PixelFormats/Bgr565.cs | 16 ++ src/ImageSharp/PixelFormats/Bgra32.cs | 29 +++ src/ImageSharp/PixelFormats/Bgra4444.cs | 16 ++ src/ImageSharp/PixelFormats/Bgra5551.cs | 16 ++ src/ImageSharp/PixelFormats/Byte4.cs | 16 ++ src/ImageSharp/PixelFormats/Gray16.cs | 33 ++- src/ImageSharp/PixelFormats/Gray8.cs | 3 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 16 ++ src/ImageSharp/PixelFormats/HalfVector2.cs | 16 ++ src/ImageSharp/PixelFormats/HalfVector4.cs | 16 ++ src/ImageSharp/PixelFormats/IPixel.cs | 24 ++ .../PixelFormats/NormalizedByte2.cs | 16 ++ .../PixelFormats/NormalizedByte4.cs | 16 ++ .../PixelFormats/NormalizedShort2.cs | 16 ++ .../PixelFormats/NormalizedShort4.cs | 16 ++ src/ImageSharp/PixelFormats/Rg32.cs | 16 ++ src/ImageSharp/PixelFormats/Rgb24.cs | 27 +++ src/ImageSharp/PixelFormats/Rgb48.cs | 33 +++ src/ImageSharp/PixelFormats/Rgba1010102.cs | 16 ++ src/ImageSharp/PixelFormats/Rgba32.cs | 35 +++ src/ImageSharp/PixelFormats/Rgba64.cs | 29 +++ src/ImageSharp/PixelFormats/RgbaVector.cs | 16 ++ src/ImageSharp/PixelFormats/Short2.cs | 16 ++ src/ImageSharp/PixelFormats/Short4.cs | 16 ++ .../PixelFormats/Gray16Tests.cs | 211 ++++++++++++++++++ 28 files changed, 748 insertions(+), 5 deletions(-) create mode 100644 tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index a8d97d31a2..d795931af3 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -168,6 +168,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.B = 0; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackedValue = 255; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackedValue = 0; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackedValue = 255; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackedValue = 0; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 51d3964ef8..0249bb6af9 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -289,6 +290,35 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = this.A; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.A = 255; + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + this.A = 255; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// /// Converts the pixel to format. /// diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index fc283b5684..bc8e2324ce 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -172,6 +172,33 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = byte.MaxValue; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 570b975dba..53f15ecb3b 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -187,6 +187,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 233df2f29e..304f815359 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -215,6 +215,35 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ToBgra32(ref Bgra32 dest) => dest = this; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.R = source.PackedValue; + this.R = source.PackedValue; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// /// Converts the pixel to format. /// diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 90f967f898..f684bec339 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -178,6 +178,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 3a18c03e83..1044a0febf 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -178,6 +178,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index bb1b350f07..aea3aec655 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -179,6 +179,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index a7e50e3667..6fda8b0817 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Initializes a new instance of the struct. /// /// The gray component - public Gray16(byte gray) + public Gray16(ushort gray) { this.PackedValue = gray; } @@ -185,6 +185,34 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.PackedValue = (ushort)(source.PackedValue * 255); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) + { + dest.PackedValue = (byte)(((this.PackedValue * 255) + 32895) >> 16); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + this.PackedValue = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) + { + dest.PackedValue = this.PackedValue; + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => @@ -252,9 +280,8 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ushort Pack(float r, float g, float b) { - float sum = r + g + b; float val = (r * Rx) + (g * Gx) + (b * Bx); - return (ushort)Math.Round(val * 65535f / sum); // TODO: if this is correct, Rx, Gx, Bx consts could be scaled by 65535f directly! + return (ushort)Math.Round(val * 65535f); } /// diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index db05395431..1509f8ea9f 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -257,9 +257,8 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte Pack(float r, float g, float b) { - float sum = r + g + b; float val = (r * Rx) + (g * Gx) + (b * Bx); - return (byte)Math.Round(val * 255 / sum); // TODO: if this is correct, Rx, Gx, Bx consts could be scaled by 255 directly! + return (byte)Math.Round(val * 255); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 09b4636492..b392910a67 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -192,6 +192,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index befa49736c..ac70f4fbcc 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -207,6 +207,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 885e022921..9bdae99abe 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -200,6 +200,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index ae09af626c..382c8541d6 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -126,5 +126,29 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The destination pixel to write to void ToBgra32(ref Bgra32 dest); + + /// + /// Packs the Pixel from an value. + /// + /// The value. + void PackFromGray8(Gray8 source); + + /// + /// Converts the pixel to format. + /// + /// The destination pixel to write to. + void ToGray8(ref Gray8 dest); + + /// + /// Packs the Pixel from an value. + /// + /// The value. + void PackFromGray16(Gray16 source); + + /// + /// Converts the pixel tgo value. + /// + /// The destination pixel to write to. + void ToGray16(ref Gray16 dest); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 8592fdd6a7..cd9fa65fbe 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -226,6 +226,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 293d536e53..9b53adeccf 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -219,6 +219,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 1ced412d06..3319a10927 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -213,6 +213,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 25b26fa7f7..7a74a44349 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -221,6 +221,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index e5ceeacec2..e4bed1275b 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -191,6 +191,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)vector.W; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index d7e1c47ec0..4c5aef5438 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -166,6 +166,33 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = byte.MaxValue; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 2d92b0e4e3..7784c49ffb 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -210,6 +210,39 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + var val = (ushort)(source.PackedValue * 255); + this.R = val; + this.G = val; + this.B = val; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) + { + dest.PackFromRgb48(this); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) + { + dest.PackFromRgb48(this); + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this = source; diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 94fb7a41e6..6dd5f7b544 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -185,6 +185,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index cf66538c52..aab9fad928 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -336,6 +336,41 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = this.A; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = 0; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) + { + dest.PackFromRgba32(this); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); + this.R = val; + this.G = val; + this.B = val; + this.A = 0; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) + { + dest.PackFromRgba32(this); + } + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromScaledVector4(Vector4 vector) diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 8e6be1e8c4..5c3187856e 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -274,6 +274,35 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)(((this.A * 255) + 32895) >> 16); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) + { + ushort x = (ushort)(source.PackedValue * 255); + this.R = x; + this.G = x; + this.B = x; + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// public override bool Equals(object obj) { diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index dd5f77b80f..3ab45a66ef 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -298,6 +298,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 9fc7618b91..331c5fb208 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -207,6 +207,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = 255; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 641f154f94..4a3d89ad8b 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -213,6 +213,22 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = (byte)MathF.Round(vector.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray8(ref Gray8 dest) => dest.PackFromVector4(this.ToVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ToGray16(ref Gray16 dest) => dest.PackFromVector4(this.ToVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs new file mode 100644 index 0000000000..2525ee3796 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -0,0 +1,211 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Gray16Tests + { + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + [InlineData(42)] + public void Gray16_PackedValue_EqualsInput(ushort input) + { + Assert.Equal(input, new Gray16(input).PackedValue); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToVector4(ushort input) + { + // arrange + var gray = new Gray16(input); + + // act + var actual = gray.ToVector4(); + + // assert + Assert.Equal(input, actual.X); + Assert.Equal(input, actual.Y); + Assert.Equal(input, actual.Z); + Assert.Equal(1, actual.W); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToScaledVector4(ushort input) + { + // arrange + var gray = new Gray16(input); + + // act + var actual = gray.ToScaledVector4(); + + // assert + float scaledInput = input / 65535f; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Fact] + public void Gray16_PackFromScaledVector4() + { + // arrange + Gray16 gray = default; + int expected = 32767; + Vector4 scaled = new Gray16((ushort)expected).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + ushort actual = gray.PackedValue; + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToRgb24() + { + // arrange + Rgb24 actual = default; + Gray16 gray = default; + var expected = new Rgb24(128, 128, 128); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgb24(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToRgba32() + { + // arrange + Rgba32 actual = default; + Gray16 gray = default; + var expected = new Rgba32(128, 128, 128, 255); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgba32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToBgr24() + { + // arrange + Bgr24 actual = default; + Gray16 gray = default; + var expected = new Bgr24(128, 128, 128); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToBgr24(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToBgra32() + { + // arrange + Bgra32 actual = default; + Gray16 gray = default; + var expected = new Bgra32(128,128,128); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToBgra32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToArgb32() + { + // arrange + Gray16 gray = default; + Argb32 actual = default; + var expected = new Argb32(128, 128, 128); + Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToArgb32(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromScaledVector4_ToRgba64() + { + // arrange + Gray16 gray = default; + Rgba64 actual = default; + var expected = new Rgba64(65535, 65535, 65535, 65535); + Vector4 scaled = new Gray16(65535).ToScaledVector4(); + + // act + gray.PackFromScaledVector4(scaled); + gray.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromRgb48_ToRgb48() + { + // arrange + var gray = default(Gray16); + var actual = default(Rgb48); + var expected = new Rgb48(0, 0, 0); + + // act + gray.PackFromRgb48(expected); + gray.ToRgb48(ref actual); + + // assert + Assert.Equal(expected, actual); + } + + [Fact] + public void Gray16_PackFromRgba64_ToRgba64() + { + // arrange + var gray = default(Gray16); + var actual = default(Rgba64); + var expected = new Rgba64(0, 0, 0, 65535); + + // act + gray.PackFromRgba64(expected); + gray.ToRgba64(ref actual); + + // assert + Assert.Equal(expected, actual); + } + } +} From 5d35bcddcc2b435009ad7e1eaf26b760d601ad0a Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 23:55:34 +0200 Subject: [PATCH 006/238] #718: add missing inheritdoc comments --- src/ImageSharp/PixelFormats/Gray8.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index 1509f8ea9f..916e199d07 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -195,9 +195,11 @@ namespace SixLabors.ImageSharp.PixelFormats public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromGray16(Gray16 source) => this.PackedValue = (byte)(source.PackedValue / 255); From c8efad0d15f2a2de2304f382075f3d48f620c9f8 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 7 Oct 2018 00:08:42 +0200 Subject: [PATCH 007/238] #718: add missing documentation --- src/ImageSharp/PixelFormats/Gray16.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index 6fda8b0817..06da2867a9 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -287,7 +287,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Packs the into a byte. /// - /// + /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] private byte PackedAsByte() { From 1533c4cbcb32f331ce3ca6af526c7998ae96c4b5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 8 Oct 2018 19:00:01 +0100 Subject: [PATCH 008/238] Fix Gray8 --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 67 +++++++ src/ImageSharp/PixelFormats/Alpha8.cs | 105 +++-------- src/ImageSharp/PixelFormats/Gray8.cs | 188 +++++++++----------- 3 files changed, 176 insertions(+), 184 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index c15e0a7329..f9ade4cfe3 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -13,6 +13,73 @@ namespace SixLabors.ImageSharp /// internal static class ImageMaths { + /// + /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static byte GetBT709LuminanceBytes(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F)); + + /// + /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static ushort GetBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); + + /// + /// Scales a value from a 16 bit to it's 8 bit equivalent. + /// + /// The 8 bit compoonent value. + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static byte DownScaleFrom16BitTo8Bit(ushort component) + { + // To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is: + // + // (V * 255) / 65535 + // + // This reduces to round(V / 257), or floor((V + 128.5)/257) + // + // Represent V as the two byte value vhi.vlo. Make a guess that the + // result is the top byte of V, vhi, then the correction to this value + // is: + // + // error = floor(((V-vhi.vhi) + 128.5) / 257) + // = floor(((vlo-vhi) + 128.5) / 257) + // + // This can be approximated using integer arithmetic (and a signed + // shift): + // + // error = (vlo-vhi+128) >> 8; + // + // The approximate differs from the exact answer only when (vlo-vhi) is + // 128; it then gives a correction of +1 when the exact correction is + // 0. This gives 128 errors. The exact answer (correct for all 16-bit + // input values) is: + // + // error = (vlo-vhi+128)*65535 >> 24; + // + // An alternative arithmetic calculation which also gives no errors is: + // + // (V * 255 + 32895) >> 16 + return (byte)(((component * 255) + 32895) >> 16); + } + + /// + /// Scales a value from an 8 bit to it's 16 bit equivalent. + /// + /// The 8 bit compoonent value. + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257); + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index d795931af3..177ce81efd 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -19,10 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Initializes a new instance of the struct. /// /// The alpha component - public Alpha8(float alpha) - { - this.PackedValue = Pack(alpha); - } + public Alpha8(float alpha) => this.PackedValue = Pack(alpha); /// public byte PackedValue { get; set; } @@ -40,10 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Alpha8 left, Alpha8 right) - { - return left.PackedValue == right.PackedValue; - } + public static bool operator ==(Alpha8 left, Alpha8 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -54,77 +48,48 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is not equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Alpha8 left, Alpha8 right) - { - return left.PackedValue != right.PackedValue; - } + public static bool operator !=(Alpha8 left, Alpha8 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + public Vector4 ToScaledVector4() => this.ToVector4(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.W); - } + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(0, 0, 0, this.PackedValue / 255F); - } + public Vector4 ToVector4() => new Vector4(0, 0, 0, this.PackedValue / 255F); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackedValue = source.A; - } + public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = source.A; - } + public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = source.A; - } + public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest = default(Rgb24); - } + public void ToRgb24(ref Rgb24 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ToRgba32(ref Rgba32 dest) { - dest.R = 0; - dest.G = 0; - dest.B = 0; + dest.Rgb = default; dest.A = this.PackedValue; } @@ -140,10 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest = default(Bgr24); - } + public void ToBgr24(ref Bgr24 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -161,28 +123,23 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - } + public void ToRgb48(ref Rgb48 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray8(Gray8 source) => this.PackedValue = 255; + public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackedValue = 0; + public void ToGray8(ref Gray8 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) => this.PackedValue = 255; + public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackedValue = 0; + public void ToGray16(ref Gray16 dest) => dest = default; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -190,17 +147,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public void ToRgba64(ref Rgba64 dest) + { + dest.Rgb = default; + dest.A = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); + } /// /// Compares an object with the packed vector. /// /// The object to compare. /// True if the object is equal to the packed vector. - public override bool Equals(object obj) - { - return obj is Alpha8 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Alpha8 other && this.Equals(other); /// /// Compares another Alpha8 packed vector with the packed vector. @@ -208,19 +166,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// The Alpha8 packed vector to compare. /// True if the packed vectors are equal. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Alpha8 other) - { - return this.PackedValue == other.PackedValue; - } + public bool Equals(Alpha8 other) => this.PackedValue.Equals(other.PackedValue); /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() - { - return (this.PackedValue / 255F).ToString(); - } + public override string ToString() => (this.PackedValue / 255F).ToString(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -232,9 +184,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// The float containing the value to pack. /// The containing the packed values. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte Pack(float alpha) - { - return (byte)Math.Round(alpha.Clamp(0, 1) * 255F); - } + private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1) * 255F); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index 916e199d07..0a41a6ecc6 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -30,14 +29,21 @@ namespace SixLabors.ImageSharp.PixelFormats /// private const float Bx = .0722F; + /// + /// The maximum byte value. + /// + private static readonly Vector4 MaxBytes = new Vector4(255F); + + /// + /// The half vector value. + /// + private static readonly Vector4 Half = new Vector4(0.5F); + /// /// Initializes a new instance of the struct. /// /// The gray component - public Gray8(byte gray) - { - this.PackedValue = gray; - } + public Gray8(byte gray) => this.PackedValue = gray; /// public byte PackedValue { get; set; } @@ -45,20 +51,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Gray8 left, Gray8 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Gray8 left, Gray8 right) => left.PackedValue.Equals(right.PackedValue); /// /// Compares two objects for equality. @@ -68,67 +67,54 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Gray8 left, Gray8 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Gray8 left, Gray8 right) => !left.PackedValue.Equals(right.PackedValue); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaledGray = this.PackedValue / 255f; - return new Vector4(scaledGray, scaledGray, scaledGray, 1.0f); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + float luminance = (vector.X * Rx) + (vector.Y * Gx) + (vector.Z * Bx); + + this.PackedValue = (byte)luminance; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { - return new Vector4(this.PackedValue, this.PackedValue, this.PackedValue, 1.0f); + float rgb = this.PackedValue / 255F; + return new Vector4(rgb, rgb, rgb, 1F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackedValue = Pack(source.R, source.G, source.B); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = Pack(source.R, source.G, source.B); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = Pack(source.R, source.G, source.B); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToRgb24(ref Rgb24 dest) { dest.R = this.PackedValue; @@ -137,27 +123,27 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { dest.R = this.PackedValue; dest.G = this.PackedValue; dest.B = this.PackedValue; - dest.A = 255; + dest.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToArgb32(ref Argb32 dest) { dest.R = this.PackedValue; dest.G = this.PackedValue; dest.B = this.PackedValue; - dest.A = 255; + dest.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToBgr24(ref Bgr24 dest) { dest.R = this.PackedValue; @@ -166,101 +152,91 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToBgra32(ref Bgra32 dest) { dest.R = this.PackedValue; dest.G = this.PackedValue; dest.B = this.PackedValue; - dest.A = 255; + dest.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => - this.PackedValue = Pack(source.R, source.G, source.B); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) + => this.PackedValue = ImageMaths.GetBT709LuminanceBytes( + ImageMaths.DownScaleFrom16BitTo8Bit(source.R), + ImageMaths.DownScaleFrom16BitTo8Bit(source.G), + ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToRgb48(ref Rgb48 dest) { - ushort gray = (ushort)(this.PackedValue * 255); - dest.R = gray; - dest.G = gray; - dest.B = gray; + ushort luminance = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); + dest.R = luminance; + dest.G = luminance; + dest.B = luminance; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => - this.PackFromScaledVector4(source.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) + => this.PackedValue = ImageMaths.GetBT709LuminanceBytes( + ImageMaths.DownScaleFrom16BitTo8Bit(source.R), + ImageMaths.DownScaleFrom16BitTo8Bit(source.G), + ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) => this.PackedValue = (byte)(source.PackedValue / 255); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba64(ref Rgba64 dest) + { + ushort luminance = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); + dest.R = luminance; + dest.G = luminance; + dest.B = luminance; + dest.A = ushort.MaxValue; + } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void ToGray8(ref Gray8 dest) => dest.PackedValue = this.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackedValue = (ushort)(this.PackedValue * 255); + [MethodImpl(InliningOptions.ShortMethod)] + public void ToGray16(ref Gray16 dest) => dest.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); /// /// Compares an object with the packed vector. /// /// The object to compare. /// True if the object is equal to the packed vector. - public override bool Equals(object obj) - { - return obj is Gray8 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Gray8 other && this.Equals(other); /// /// Compares another packed vector with the packed vector. /// /// The Gray8 packed vector to compare. /// True if the packed vectors are equal. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Gray8 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue); /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() - { - return (this.PackedValue / 255F).ToString(); - } + public override string ToString() => $"Gray8({this.PackedValue}"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Packs a into a byte. - /// - /// Red value of the color to pack. - /// Green value of the color to pack. - /// Blue value of the color to pack. - /// The containing the packed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte Pack(float r, float g, float b) - { - float val = (r * Rx) + (g * Gx) + (b * Bx); - return (byte)Math.Round(val * 255); - } } } \ No newline at end of file From 295021928737eb149b949b39cd8dc77e7581e238 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 9 Oct 2018 23:57:23 +0100 Subject: [PATCH 009/238] Update and normalise pixel format + disable out of date tests --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 4 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 34 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 116 +- src/ImageSharp/PixelFormats/Alpha8.cs | 102 +- src/ImageSharp/PixelFormats/Argb32.cs | 260 +--- src/ImageSharp/PixelFormats/Bgr24.cs | 191 +-- src/ImageSharp/PixelFormats/Bgr565.cs | 216 +-- src/ImageSharp/PixelFormats/Bgra32.cs | 230 +-- src/ImageSharp/PixelFormats/Bgra4444.cs | 200 +-- src/ImageSharp/PixelFormats/Bgra5551.cs | 209 +-- src/ImageSharp/PixelFormats/Byte4.cs | 182 +-- .../PixelOperations{TPixel}.Generated.cs | 113 +- .../PixelOperations{TPixel}.Generated.tt | 8 +- .../Rgba32.PixelOperations.Generated.cs | 12 +- .../Rgba32.PixelOperations.Generated.tt | 12 +- src/ImageSharp/PixelFormats/Gray16.cs | 262 +--- src/ImageSharp/PixelFormats/Gray8.cs | 136 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 200 +-- src/ImageSharp/PixelFormats/HalfTypeHelper.cs | 12 +- src/ImageSharp/PixelFormats/HalfVector2.cs | 231 +-- src/ImageSharp/PixelFormats/HalfVector4.cs | 203 +-- src/ImageSharp/PixelFormats/IPixel.cs | 96 +- .../PixelFormats/NormalizedByte2.cs | 263 +--- .../PixelFormats/NormalizedByte4.cs | 244 +-- .../PixelFormats/NormalizedShort2.cs | 253 +-- .../PixelFormats/NormalizedShort4.cs | 257 +--- src/ImageSharp/PixelFormats/Rg32.cs | 230 +-- src/ImageSharp/PixelFormats/Rgb24.cs | 185 +-- src/ImageSharp/PixelFormats/Rgb48.cs | 206 +-- src/ImageSharp/PixelFormats/Rgba1010102.cs | 222 +-- src/ImageSharp/PixelFormats/Rgba32.cs | 306 +--- src/ImageSharp/PixelFormats/Rgba64.cs | 248 +-- src/ImageSharp/PixelFormats/RgbaVector.cs | 355 +---- src/ImageSharp/PixelFormats/Short2.cs | 250 +-- src/ImageSharp/PixelFormats/Short4.cs | 248 +-- .../BinaryErrorDiffusionProcessor.cs | 11 +- .../BinaryOrderedDitherProcessor.cs | 9 +- .../Binarization/BinaryThresholdProcessor.cs | 9 +- .../ErrorDiffusionPaletteProcessor.cs | 12 +- .../OrderedDitherPaletteProcessor.cs | 15 +- .../OctreeFrameQuantizer{TPixel}.cs | 49 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 48 +- .../ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs | 32 +- .../Color/Bulk/ToXyzw.cs | 14 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 8 +- tests/ImageSharp.Tests/Issues/Issue594.cs | 174 +-- .../PixelFormats/Alpha8Tests.cs | 266 ++-- .../PixelFormats/Argb32Tests.cs | 308 ++-- .../PixelFormats/Bgr24Tests.cs | 150 +- .../PixelFormats/Bgr565Tests.cs | 212 +-- .../PixelFormats/Bgra32Tests.cs | 150 +- .../PixelFormats/Bgra4444Tests.cs | 308 ++-- .../PixelFormats/Bgra5551Tests.cs | 308 ++-- .../PixelFormats/Byte4Tests.cs | 308 ++-- .../PixelFormats/ColorConstructorTests.cs | 151 -- .../PixelFormats/ColorEqualityTests.cs | 216 --- .../PixelFormats/ColorPackingTests.cs | 88 -- .../PixelFormats/Gray16Tests.cs | 376 ++--- .../PixelFormats/Gray8Tests.cs | 302 ++-- .../PixelFormats/HalfSingleTests.cs | 212 +-- .../PixelFormats/HalfVector2Tests.cs | 212 +-- .../PixelFormats/HalfVector4Tests.cs | 308 ++-- .../PixelFormats/NormalizedByte2Tests.cs | 244 +-- .../PixelFormats/NormalizedByte4Tests.cs | 278 ++-- .../PixelFormats/NormalizedShort2Tests.cs | 246 +-- .../PixelFormats/NormalizedShort4Tests.cs | 278 ++-- .../PixelFormats/PixelOperationsTests.cs | 1354 ++++++++--------- .../PixelFormats/Rg32Tests.cs | 182 +-- .../PixelFormats/Rgb24Tests.cs | 350 ++--- .../PixelFormats/Rgb48Tests.cs | 391 +++-- .../PixelFormats/Rgba1010102Tests.cs | 278 ++-- .../PixelFormats/Rgba32Tests.cs | 110 +- .../PixelFormats/Rgba64Tests.cs | 221 +-- .../PixelFormats/RgbaVectorTests.cs | 50 +- .../PixelFormats/Short2Tests.cs | 74 +- .../PixelFormats/Short4Tests.cs | 74 +- .../PixelFormats/UnPackedPixelTests.cs | 64 +- .../Transforms/AffineTransformTests.cs | 13 +- .../Quantization/QuantizedImageTests.cs | 5 +- .../TestUtilities/ImagingTestCaseUtility.cs | 12 +- .../TestUtilities/TestUtils.cs | 16 +- .../Tests/TestImageProviderTests.cs | 38 +- 83 files changed, 5479 insertions(+), 9355 deletions(-) delete mode 100644 tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs delete mode 100644 tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs delete mode 100644 tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index f9ade4cfe3..7bf73245f7 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static byte GetBT709LuminanceBytes(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F)); + public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F)); /// /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static ushort GetBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); + public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); /// /// Scales a value from a 16 bit to it's 8 bit equivalent. diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 44e42528cf..186ff812f7 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -101,9 +101,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp var fileHeader = new BmpFileHeader( type: 19778, // BM - offset: 54, + fileSize: 54 + infoHeader.ImageSize, reserved: 0, - fileSize: 54 + infoHeader.ImageSize); + offset: 54); #if NETCOREAPP2_1 Span buffer = stackalloc byte[40]; diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ae0366e6e6..f00a6b61e3 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -210,16 +211,20 @@ namespace SixLabors.ImageSharp.Formats.Gif { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; - Rgba32 trans = default; + int length = quantized.Palette.Length; - ref TPixel paletteRef = ref MemoryMarshal.GetReference(quantized.Palette.AsSpan()); - for (int i = quantized.Palette.Length - 1; i >= 0; i--) + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(length)) { - ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); - entry.ToRgba32(ref trans); - if (trans.Equals(default)) + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan, length); + + for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - index = i; + if (Unsafe.Add(ref paletteRef, i).Equals(default)) + { + index = i; + } } } @@ -406,24 +411,13 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteColorTable(QuantizedFrame image, Stream stream) where TPixel : struct, IPixel { - int pixelCount = image.Palette.Length; - // The maximium number of colors for the bit depth int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; - Rgb24 rgb = default; + int pixelCount = image.Palette.Length; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) { - ref TPixel paletteRef = ref MemoryMarshal.GetReference(image.Palette.AsSpan()); - ref Rgb24 rgb24Ref = ref Unsafe.As(ref MemoryMarshal.GetReference(colorTable.GetSpan())); - for (int i = 0; i < pixelCount; i++) - { - ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); - entry.ToRgb24(ref rgb); - Unsafe.Add(ref rgb24Ref, i) = rgb; - } - - // Write the palette to the stream + PixelOperations.Instance.ToRgb24Bytes(image.Palette.AsSpan(), colorTable.GetSpan(), pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index a46d83707e..1e9dbc71a1 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; @@ -312,11 +313,6 @@ namespace SixLabors.ImageSharp.Formats.Png private void CollectGrayscaleBytes(ReadOnlySpan rowSpan) where TPixel : struct, IPixel { - // Use ITU-R recommendation 709 to match libpng. - const float RX = .2126F; - const float GX = .7152F; - const float BX = .0722F; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); Span rawScanlineSpan = this.rawScanline.GetSpan(); ref byte rawScanlineSpanRef = ref MemoryMarshal.GetReference(rawScanlineSpan); @@ -327,12 +323,18 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.use16Bit) { // 16 bit grayscale - Rgb48 rgb = default; - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) + using (IMemoryOwner luminanceBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); - ushort luminance = (ushort)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); + Span luminanceSpan = luminanceBuffer.GetSpan(); + ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan); + PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) + { + Gray16 luminance = Unsafe.Add(ref luminanceRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance.PackedValue); + } } } else @@ -340,12 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.bitDepth == 8) { // 8 bit grayscale - Rgb24 rgb = default; - for (int x = 0; x < rowSpan.Length; x++) - { - Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); - Unsafe.Add(ref rawScanlineSpanRef, x) = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); - } + PixelOperations.Instance.ToGray8Bytes(rowSpan, rawScanlineSpan, rowSpan.Length); } else { @@ -356,14 +353,9 @@ namespace SixLabors.ImageSharp.Formats.Png Span tempSpan = temp.GetSpan(); ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan); - Rgb24 rgb = default; - for (int x = 0; x < rowSpan.Length; x++) - { - Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); - float luminance = ((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)) / scaleFactor; - Unsafe.Add(ref tempSpanRef, x) = (byte)luminance; - this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth); - } + // We need to first create an array of luminance bytes then scale them down to the correct bit depth. + PixelOperations.Instance.ToGray8Bytes(rowSpan, tempSpan, rowSpan.Length); + this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor); } } } @@ -373,23 +365,31 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.use16Bit) { // 16 bit grayscale + alpha - Rgba64 rgba = default; - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 4) + // TODO: Should we consider in the future a GrayAlpha32 type. + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); - ushort luminance = (ushort)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A); + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4) + { + Rgba64 rgba = Unsafe.Add(ref rgbaRef, x); + ushort luminance = ImageMaths.Get16BitBT709Luminance(rgba.R, rgba.G, rgba.B); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A); + } } } else { // 8 bit grayscale + alpha - Rgba32 rgba = default; + // TODO: Should we consider in the future a GrayAlpha16 type. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { - Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); - Unsafe.Add(ref rawScanlineSpanRef, o) = (byte)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); + var rgba = Unsafe.Add(ref rowSpanRef, x).ToRgba32(); + Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } } @@ -425,15 +425,21 @@ namespace SixLabors.ImageSharp.Formats.Png case 8: { // 16 bit Rgba - Rgba64 rgba = default; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A); + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) + { + Rgba64 rgba = Unsafe.Add(ref rgbaRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A); + } } break; @@ -442,14 +448,20 @@ namespace SixLabors.ImageSharp.Formats.Png default: { // 16 bit Rgb - Rgb48 rgb = default; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) + using (IMemoryOwner rgbBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B); + Span rgbSpan = rgbBuffer.GetSpan(); + ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan); + PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan, rowSpan.Length); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) + { + Rgb48 rgb = Unsafe.Add(ref rgbRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B); + } } break; @@ -624,7 +636,6 @@ namespace SixLabors.ImageSharp.Formats.Png TPixel[] palette = quantized.Palette; int paletteLength = Math.Min(palette.Length, 256); int colorTableLength = paletteLength * 3; - Rgba32 rgba = default; bool anyAlpha = false; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) @@ -639,7 +650,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (quantizedSpan.IndexOf((byte)i) > -1) { int offset = i * 3; - palette[i].ToRgba32(ref rgba); + var rgba = palette[i].ToRgba32(); byte alpha = rgba.A; @@ -851,7 +862,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The source span in 8 bits. /// The resultant span in . /// The bit depth. - private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits) + /// The scaling factor. + private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits, float scale = 1) { ref byte sourceRef = ref MemoryMarshal.GetReference(source); ref byte resultRef = ref MemoryMarshal.GetReference(result); @@ -864,7 +876,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int i = 0; i < source.Length; i++) { - int value = Unsafe.Add(ref sourceRef, i) & mask; + int value = ((int)MathF.Round(Unsafe.Add(ref sourceRef, i) / scale)) & mask; v |= value << shift; if (shift == 0) diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 177ce81efd..91be2efdd2 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(Alpha8 left, Alpha8 right) => left.Equals(right); /// @@ -47,112 +47,60 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Alpha8 left, Alpha8 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() => new Vector4(0, 0, 0, this.PackedValue / 255F); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) => dest = default; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.Rgb = default; - dest.A = this.PackedValue; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) => dest = default; + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(0, 0, 0, this.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = default; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest = default; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest = default; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) - { - dest.Rgb = default; - dest.A = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); - } - /// /// Compares an object with the packed vector. /// @@ -165,17 +113,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The Alpha8 packed vector to compare. /// True if the packed vectors are equal. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Alpha8 other) => this.PackedValue.Equals(other.PackedValue); /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() => (this.PackedValue / 255F).ToString(); + public override string ToString() => $"Alpha8({this.PackedValue})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// @@ -183,7 +131,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The float containing the value to pack. /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1) * 255F); + [MethodImpl(InliningOptions.ShortMethod)] + private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1F) * 255F); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 0249bb6af9..0da8516a3e 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -58,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(byte r, byte g, byte b) { this.R = r; @@ -74,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(byte r, byte g, byte b, byte a) { this.R = r; @@ -90,12 +89,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(float r, float g, float b, float a = 1) - : this() - { - this.Pack(r, g, b, a); - } + : this() => this.Pack(r, g, b, a); /// /// Initializes a new instance of the struct. @@ -103,12 +99,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(Vector3 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -116,12 +109,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(Vector4 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -129,22 +119,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The packed value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(uint packed) - : this() - { - this.Argb = packed; - } + : this() => this.Argb = packed; /// /// Gets or sets the packed representation of the Argb32 struct. /// public uint Argb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -158,20 +145,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Argb32 left, Argb32 right) - { - return left.Argb == right.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Argb32 left, Argb32 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -181,62 +161,34 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Argb32 left, Argb32 right) - { - return left.Argb != right.Argb; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = source.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -245,164 +197,84 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest = this; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { - this.A = 255; this.R = source.PackedValue; this.G = source.PackedValue; this.B = source.PackedValue; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; - this.A = 255; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override bool Equals(object obj) => obj is Argb32 argb32 && this.Equals(argb32); /// - public override bool Equals(object obj) - { - return obj is Argb32 argb32 && this.Equals(argb32); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Argb32 other) - { - return this.Argb == other.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Argb32 other) => this.Argb == other.Argb; /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + public override string ToString() => $"Argb({this.A}, {this.R}, {this.G}, {this.B})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.Argb.GetHashCode(); /// /// Gets the representation without normalizing to [0, 1] /// /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } + [MethodImpl(InliningOptions.ShortMethod)] + internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); /// /// Packs the four floats into a color. @@ -411,7 +283,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(float x, float y, float z, float w) { var value = new Vector4(x, y, z, w); @@ -422,7 +294,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector3 vector) { var value = new Vector4(vector, 1); @@ -433,7 +305,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index e1bb8a0ce1..063fed5221 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgr24(byte r, byte g, byte b) { this.R = r; @@ -49,39 +49,54 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = b; } + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgr24 left, Bgr24 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); + /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgr24 other) - { - return this.R == other.R && this.G == other.G && this.B == other.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - public override bool Equals(object obj) - { - return obj is Bgr24 other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - return HashHelpers.Combine(hash, this.B.GetHashCode()); + Rgba32 rgba = default; + rgba.PackFromVector4(vector); + this.PackFromRgba32(rgba); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = source.Bgr; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -90,7 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -99,81 +114,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - public void ToBgr24(ref Bgr24 dest) - { - dest = this; - } - - /// - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { this.R = source.PackedValue; @@ -182,53 +123,57 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = source.Bgr; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgr24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); + + /// + public override bool Equals(object obj) => obj is Bgr24 other && this.Equals(other); /// - public override string ToString() + public override string ToString() => $"Bgra({this.B}, {this.G}, {this.R})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() { - return $"({this.B},{this.G},{this.R})"; + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 53f15ecb3b..5b19fb25c1 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -8,7 +8,8 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats { /// - /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x and z components use 5 bits, and the y component uses 6 bits. + /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. + /// The x and z components use 5 bits, and the y component uses 6 bits. /// /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// @@ -22,8 +23,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component public Bgr565(float x, float y, float z) + : this(new Vector3(x, y, z)) { - this.PackedValue = Pack(x, y, z); } /// @@ -32,10 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed value. /// - public Bgr565(Vector3 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); - } + public Bgr565(Vector3 vector) => this.PackedValue = Pack(ref vector); /// public ushort PackedValue { get; set; } @@ -48,11 +46,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgr565 left, Bgr565 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgr565 left, Bgr565 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -62,199 +57,104 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgr565 left, Bgr565 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector3 ToVector3() - { - return new Vector3( - ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), - ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), - (this.PackedValue & 0x1F) * (1F / 31F)); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + var vector3 = new Vector3(vector.X, vector.Y, vector.Z); + this.PackedValue = Pack(ref vector3); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector3(), 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector3(), 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromVector4(source.ToVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector3 ToVector3() { - return obj is Bgr565 other && this.Equals(other); + return new Vector3( + ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), + ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), + (this.PackedValue & 0x1F) * (1F / 31F)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgr565 other) - { - return this.PackedValue == other.PackedValue; - } + public override bool Equals(object obj) => obj is Bgr565 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgr565 other) => this.PackedValue.Equals(other.PackedValue); /// public override string ToString() { - return this.ToVector3().ToString(); + var vector = this.ToVector3(); + return $"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector3 vector) { - return (ushort)((((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 11) - | (((int)Math.Round(y.Clamp(0, 1) * 63F) & 0x3F) << 5) - | ((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F)); + vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + + return (ushort)((((int)Math.Round(vector.X * 31F) & 0x1F) << 11) + | (((int)Math.Round(vector.Y * 63F) & 0x3F) << 5) + | ((int)Math.Round(vector.Z * 31F) & 0x1F)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index c6fa4cf67e..6fd0867797 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgra32(byte r, byte g, byte b) { this.R = r; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgra32(byte r, byte g, byte b, byte a) { this.R = r; @@ -84,10 +84,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint Bgra { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -98,71 +98,49 @@ namespace SixLabors.ImageSharp.PixelFormats set => this.Bgra = value; } - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - public bool Equals(Bgra32 other) - { - return this.Bgra == other.Bgra; - } - - /// - public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); - - /// - public override int GetHashCode() => this.Bgra.GetHashCode(); + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right); /// - /// Gets the representation without normalizing to [0, 1] + /// Compares two objects for equality. /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -172,132 +150,88 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = source.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) => dest = Unsafe.As(ref this); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) => dest = this; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { this.R = source.PackedValue; - this.R = source.PackedValue; - this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; + } - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); + + /// + public bool Equals(Bgra32 other) => this.Bgra.Equals(other.Bgra); + + /// + public override int GetHashCode() => this.Bgra.GetHashCode(); + + /// + public override string ToString() => $"Bgra32({this.B}, {this.G}, {this.R}, {this.A})"; + + /// + /// Gets the representation without normalizing to [0, 1] + /// + /// A of values in [0, 255] + [MethodImpl(InliningOptions.ShortMethod)] + internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; @@ -309,11 +243,5 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = (byte)vector.Z; this.A = (byte)vector.W; } - - /// - public override string ToString() - { - return $"({this.B},{this.G},{this.R},{this.A})"; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index f684bec339..8a5e3f76b3 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -23,18 +23,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component /// The w-component public Bgra4444(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } /// /// Initializes a new instance of the struct. /// /// The vector containing the components for the packed vector. - public Bgra4444(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + public Bgra4444(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public ushort PackedValue { get; set; } @@ -47,11 +44,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgra4444 left, Bgra4444 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra4444 left, Bgra4444 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -61,193 +55,95 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgra4444 left, Bgra4444 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { const float Max = 1 / 15F; return new Vector4( - ((this.PackedValue >> 8) & 0x0F) * Max, - ((this.PackedValue >> 4) & 0x0F) * Max, - (this.PackedValue & 0x0F) * Max, - ((this.PackedValue >> 12) & 0x0F) * Max); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; + (this.PackedValue >> 8) & 0x0F, + (this.PackedValue >> 4) & 0x0F, + this.PackedValue & 0x0F, + (this.PackedValue >> 12) & 0x0F) * Max; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Bgra4444 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Bgra4444 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgra4444 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgra4444 other) => this.PackedValue.Equals(other.PackedValue); /// public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return $"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector4 vector) { - return (ushort)((((int)Math.Round(w.Clamp(0, 1) * 15F) & 0x0F) << 12) | - (((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) | - (((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) | - ((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F)); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12) + | (((int)Math.Round(vector.X * 15F) & 0x0F) << 8) + | (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4) + | ((int)Math.Round(vector.Z * 15F) & 0x0F)); } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 1044a0febf..25f289b846 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -8,7 +8,8 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats { /// - /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x , y and z components use 5 bits, and the w component uses 1 bit. + /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. + /// The x , y and z components use 5 bits, and the w component uses 1 bit. /// /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// @@ -23,8 +24,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component /// The w-component public Bgra5551(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } /// @@ -33,10 +34,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - public Bgra5551(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + public Bgra5551(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public ushort PackedValue { get; set; } @@ -49,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgra5551 left, Bgra5551 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra5551 left, Bgra5551 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -63,31 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgra5551 left, Bgra5551 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -98,166 +88,67 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Bgra5551 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Bgra5551 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgra5551 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgra5551 other) => this.PackedValue.Equals(other.PackedValue); - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. + /// public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return $"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"; } - /// - /// Gets a hash code of the packed vector. - /// - /// The hash code for the packed vector. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector4 vector) { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); return (ushort)( - (((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 10) - | (((int)Math.Round(y.Clamp(0, 1) * 31F) & 0x1F) << 5) - | (((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F) << 0) - | (((int)Math.Round(w.Clamp(0, 1)) & 0x1) << 15)); + (((int)Math.Round(vector.X * 31F) & 0x1F) << 10) + | (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5) + | (((int)Math.Round(vector.Z * 31F) & 0x1F) << 0) + | (((int)Math.Round(vector.W) & 0x1) << 15)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255f; + [MethodImpl(InliningOptions.ShortMethod)] + private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index aea3aec655..fbdf4862db 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -21,10 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// A vector containing the initial values for the components of the Byte4 structure. /// - public Byte4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + public Byte4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -50,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Byte4 left, Byte4 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Byte4 left, Byte4 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -64,38 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Byte4 left, Byte4 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector * 255F); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector * 255F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4() / 255F; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4() / 255F; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -106,135 +88,53 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToByteScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToByteScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Byte4 byte4 && this.Equals(byte4); - } + public override bool Equals(object obj) => obj is Byte4 byte4 && this.Equals(byte4); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Byte4 other) - { - return this == other; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Byte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Returns a string representation of the current instance. - /// - /// String that represents the object. + /// public override string ToString() { - return this.PackedValue.ToString("x8"); + var vector = this.ToVector4(); + return $"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } /// @@ -242,18 +142,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(ref Vector4 vector) { const float Max = 255F; - const float Min = 0F; // Clamp the value between min and max values - // TODO: Use Vector4.Clamp() here! - uint byte4 = (uint)Math.Round(vector.X.Clamp(Min, Max)) & 0xFF; - uint byte3 = ((uint)Math.Round(vector.Y.Clamp(Min, Max)) & 0xFF) << 0x8; - uint byte2 = ((uint)Math.Round(vector.Z.Clamp(Min, Max)) & 0xFF) << 0x10; - uint byte1 = ((uint)Math.Round(vector.W.Clamp(Min, Max)) & 0xFF) << 0x18; + vector = Vector4.Clamp(vector, Vector4.Zero, new Vector4(Max)); + + uint byte4 = (uint)Math.Round(vector.X) & 0xFF; + uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; + uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 0x10; + uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 0x18; return byte4 | byte3 | byte2 | byte1; } diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index 50398eeb25..852ff73e0e 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -1,13 +1,4 @@ - - - - - - - - - -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // @@ -55,10 +46,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -74,7 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgba64(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -127,10 +116,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -146,7 +133,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgb48(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -199,10 +186,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -218,7 +203,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgba32(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -271,10 +256,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -290,7 +273,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToBgra32(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -343,10 +326,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -362,7 +343,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgb24(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -415,10 +396,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -434,7 +413,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToBgr24(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -487,10 +466,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -506,7 +483,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToArgb32(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -559,10 +536,8 @@ namespace SixLabors.ImageSharp.PixelFormats { this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); } - /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -578,7 +553,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToGray8(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -594,5 +569,75 @@ namespace SixLabors.ImageSharp.PixelFormats { this.ToGray8(sourceColors, MemoryMarshal.Cast(destBytes), count); } + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(source); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! + var temp = NamedColors.Black; + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromGray16(temp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.PackFromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); + } + /// + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// + /// The span of source pixels + /// The destination span of data. + /// The number of pixels to convert. + internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span dest, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToGray16Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + { + this.ToGray16(sourceColors, MemoryMarshal.Cast(destBytes), count); + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index b4b577e3ab..9fbe57ed9b 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -14,6 +14,7 @@ void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) { #> + /// /// Converts 'count' elements in 'source` span of data to a span of -s. /// @@ -58,7 +59,6 @@ #> /// /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . /// /// The span of source pixels /// The destination span of data. @@ -74,7 +74,7 @@ { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); - sp.To<#=pixelType#>(ref dp); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -130,5 +130,9 @@ namespace SixLabors.ImageSharp.PixelFormats GeneratePackFromMethods("Gray8", "Gray8", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Gray8"); + + GeneratePackFromMethods("Gray16", "Gray16", "temp = Unsafe.Add(ref sourceRef, i);"); + GenerateToDestFormatMethods("Gray16"); + #> } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs index e68efba252..9621505952 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - Unsafe.As(ref dp) = sp; dp.A = 255; + Unsafe.As(ref dp) = sp; dp.A = byte.MaxValue; } } @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.Bgr = sp; dp.A = 255; + dp.Bgr = sp; dp.A = byte.MaxValue; } } @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToRgba32(); + dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A; } } @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToBgra32(); + dp.PackFromRgba32(sp); } } @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToRgba32(); + dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A; } } @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToArgb32(); + dp.PackFromRgba32(sp); } } diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt index a734333390..9d9145f0b9 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt @@ -71,17 +71,17 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations { <# - GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = 255;"); + GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = byte.MaxValue;"); GenerateConvertToMethod("Rgb24", "dp = Unsafe.As(ref sp);"); - GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = 255;"); + GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = byte.MaxValue;"); GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;"); - GeneratePackFromMethod("Bgra32", "dp = sp.ToRgba32();"); - GenerateConvertToMethod("Bgra32", "dp = sp.ToBgra32();"); + GeneratePackFromMethod("Bgra32", "dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A;"); + GenerateConvertToMethod("Bgra32", "dp.PackFromRgba32(sp);"); - GeneratePackFromMethod("Argb32", "dp = sp.ToRgba32();"); - GenerateConvertToMethod("Argb32", "dp = sp.ToArgb32();"); + GeneratePackFromMethod("Argb32", "dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A;"); + GenerateConvertToMethod("Argb32", "dp.PackFromRgba32(sp);"); #> } diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index 06da2867a9..f9aada9374 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -15,29 +15,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Gray16 : IPixel, IPackedVector { - /// - /// RX as in ITU-R recommendation 709 to match libpng - /// - private const float Rx = .2126F; - - /// - /// GX as in ITU-R recommendation 709 to match libpng - /// - private const float Gx = .7152F; - - /// - /// BX as in ITU-R recommendation 709 to match libpng - /// - private const float Bx = .0722F; + private const float Max = ushort.MaxValue; /// /// Initializes a new instance of the struct. /// - /// The gray component - public Gray16(ushort gray) - { - this.PackedValue = gray; - } + /// The luminance component + public Gray16(ushort luminance) => this.PackedValue = luminance; /// public ushort PackedValue { get; set; } @@ -45,20 +29,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Gray16 left, Gray16 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Gray16 left, Gray16 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -68,230 +45,105 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Gray16 left, Gray16 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Gray16 left, Gray16 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaledGray = this.PackedValue / 65535f; // ushort.Max as float - return new Vector4(scaledGray, scaledGray, scaledGray, 1.0f); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + (ushort)MathF.Round(vector.X), + (ushort)MathF.Round(vector.Y), + (ushort)MathF.Round(vector.Z)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { - return new Vector4(this.PackedValue, this.PackedValue, this.PackedValue, 1.0f); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackedValue = Pack(source.R, source.G, source.B); + float scaled = this.PackedValue / Max; + return new Vector4(scaled, scaled, scaled, 1F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { - this.PackedValue = Pack(source.R, source.G, source.B); + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { - this.PackedValue = Pack(source.R, source.G, source.B); + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; - dest.A = 255; + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(this.PackedValue); + return new Rgba32(rgb, rgb, rgb, byte.MaxValue); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - var scaledValue = this.PackedAsByte(); - - dest.R = scaledValue; - dest.G = scaledValue; - dest.B = scaledValue; - dest.A = 255; - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray8(Gray8 source) - { - this.PackedValue = (ushort)(source.PackedValue * 255); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) => ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) - { - dest.PackedValue = (byte)(((this.PackedValue * 255) + 32895) >> 16); - } + public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) - { - this.PackedValue = source.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Gray16 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) - { - dest.PackedValue = this.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => - this.PackedValue = Pack(source.R, source.G, source.B); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => - this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - /// Compares an object with the packed vector. - /// - /// The object to compare. - /// True if the object is equal to the packed vector. - public override bool Equals(object obj) - { - return obj is Gray16 other && this.Equals(other); - } - - /// - /// Compares another packed vector with the packed vector. - /// - /// The Gray8 packed vector to compare. - /// True if the packed vectors are equal. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Gray16 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. - public override string ToString() - { - return (this.PackedValue / 65535f).ToString(); - } + public override string ToString() => $"Gray16({this.PackedValue})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Packs a into a byte. - /// - /// Red value of the color to pack. - /// Green value of the color to pack. - /// Blue value of the color to pack. - /// The containing the packed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float r, float g, float b) - { - float val = (r * Rx) + (g * Gx) + (b * Bx); - return (ushort)Math.Round(val * 65535f); - } - - /// - /// Packs the into a byte. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte PackedAsByte() - { - return (byte)(this.PackedValue >> 8); - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index 0a41a6ecc6..b1fa2b1e14 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -14,21 +14,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Gray8 : IPixel, IPackedVector { - /// - /// RX as in ITU-R recommendation 709 to match libpng - /// - private const float Rx = .2126F; - - /// - /// GX as in ITU-R recommendation 709 to match libpng - /// - private const float Gx = .7152F; - - /// - /// BX as in ITU-R recommendation 709 to match libpng - /// - private const float Bx = .0722F; - /// /// The maximum byte value. /// @@ -42,8 +27,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Initializes a new instance of the struct. /// - /// The gray component - public Gray8(byte gray) => this.PackedValue = gray; + /// The luminance component. + public Gray8(byte luminance) => this.PackedValue = luminance; /// public byte PackedValue { get; set; } @@ -57,7 +42,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is equal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(Gray8 left, Gray8 right) => left.PackedValue.Equals(right.PackedValue); + public static bool operator ==(Gray8 left, Gray8 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -68,7 +53,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is not equal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(Gray8 left, Gray8 right) => !left.PackedValue.Equals(right.PackedValue); + public static bool operator !=(Gray8 left, Gray8 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); @@ -88,9 +73,8 @@ namespace SixLabors.ImageSharp.PixelFormats vector *= MaxBytes; vector += Half; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - float luminance = (vector.X * Rx) + (vector.Y * Gx) + (vector.Z * Bx); - this.PackedValue = (byte)luminance; + this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); } /// @@ -101,138 +85,54 @@ namespace SixLabors.ImageSharp.PixelFormats return new Vector4(rgb, rgb, rgb, 1F); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); - /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); + public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.GetBT709LuminanceBytes(source.R, source.G, source.B); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - } + public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); - /// + /// [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - dest.A = byte.MaxValue; - } + public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; - /// + /// [MethodImpl(InliningOptions.ShortMethod)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - dest.A = byte.MaxValue; - } + public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); /// [MethodImpl(InliningOptions.ShortMethod)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - } + public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - dest.A = byte.MaxValue; - } + public Rgba32 ToRgba32() => new Rgba32(this.PackedValue, this.PackedValue, this.PackedValue, byte.MaxValue); /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) - => this.PackedValue = ImageMaths.GetBT709LuminanceBytes( + => this.PackedValue = ImageMaths.Get8BitBT709Luminance( ImageMaths.DownScaleFrom16BitTo8Bit(source.R), ImageMaths.DownScaleFrom16BitTo8Bit(source.G), ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgb48(ref Rgb48 dest) - { - ushort luminance = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); - dest.R = luminance; - dest.G = luminance; - dest.B = luminance; - } - /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) - => this.PackedValue = ImageMaths.GetBT709LuminanceBytes( + => this.PackedValue = ImageMaths.Get8BitBT709Luminance( ImageMaths.DownScaleFrom16BitTo8Bit(source.R), ImageMaths.DownScaleFrom16BitTo8Bit(source.G), ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba64(ref Rgba64 dest) - { - ushort luminance = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); - dest.R = luminance; - dest.G = luminance; - dest.B = luminance; - dest.A = ushort.MaxValue; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToGray8(ref Gray8 dest) => dest.PackedValue = this.PackedValue; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToGray16(ref Gray16 dest) => dest.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(this.PackedValue); - - /// - /// Compares an object with the packed vector. - /// - /// The object to compare. - /// True if the object is equal to the packed vector. + /// public override bool Equals(object obj) => obj is Gray8 other && this.Equals(other); - /// - /// Compares another packed vector with the packed vector. - /// - /// The Gray8 packed vector to compare. - /// True if the packed vectors are equal. + /// [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue); - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. + /// public override string ToString() => $"Gray8({this.PackedValue}"; /// diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index b392910a67..8048a3825d 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -28,10 +28,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Initializes a new instance of the struct. /// /// The single component. - public HalfSingle(float single) - { - this.PackedValue = HalfTypeHelper.Pack(single); - } + public HalfSingle(float single) => this.PackedValue = HalfTypeHelper.Pack(single); /// public ushort PackedValue { get; set; } @@ -39,222 +36,115 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfSingle left, HalfSingle right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfSingle left, HalfSingle right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfSingle left, HalfSingle right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float ToSingle() - { - return HalfTypeHelper.Unpack(this.PackedValue); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { float scaled = vector.X; scaled *= 2F; - scaled -= 1F; + scaled--; this.PackedValue = HalfTypeHelper.Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { float single = this.ToSingle() + 1F; single /= 2F; - return new Vector4(single, 0, 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = HalfTypeHelper.Pack(vector.X); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToSingle(), 0, 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; + return new Vector4(single, 0, 0, 1F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToSingle(), 0, 0, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + /// Expands the packed representation into a . + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public float ToSingle() => HalfTypeHelper.Unpack(this.PackedValue); /// - public override bool Equals(object obj) - { - return obj is HalfSingle other && this.Equals(other); - } + public override bool Equals(object obj) => obj is HalfSingle other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfSingle other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() - { - return this.ToSingle().ToString(); - } + public override string ToString() => $"HalfSingle({this.ToSingle():#0.##})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private Vector4 ToByteScaledVector4() { var vector = this.ToVector4(); vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; + return Vector4.Clamp(vector, Vector4.Zero, MaxBytes); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs index cf8b9f4a23..e8cfaa462e 100644 --- a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs +++ b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Helper methods for packing and unpacking floating point values /// - internal class HalfTypeHelper + internal static class HalfTypeHelper { /// /// Packs a into an @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats return (ushort)s; } - m = m | 0x00800000; + m |= 0x00800000; int t = 14 - e; int a = (1 << (t - 1)) - 1; @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.PixelFormats if ((m & 0x00800000) != 0) { m = 0; - e += 1; + e++; } if (e > 30) @@ -97,11 +97,11 @@ namespace SixLabors.ImageSharp.PixelFormats while ((mantissa & 1024) == 0) { exponent--; - mantissa = mantissa << 1; + mantissa <<= 1; } mantissa &= 0xfffffbff; - result = ((uint)((((uint)value & 0x8000) << 16) | ((exponent + 127) << 23))) | (mantissa << 13); + result = (((uint)value & 0x8000) << 16) | ((exponent + 127) << 23) | (mantissa << 13); } else { @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats } else { - result = ((((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13); + result = (((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23) | (mantissa << 13); } var uif = new Uif { U = result }; diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index ac70f4fbcc..f398f508ba 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -15,34 +14,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct HalfVector2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - /// /// Initializes a new instance of the struct. /// /// The x-component. /// The y-component. - public HalfVector2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + public HalfVector2(float x, float y) => this.PackedValue = Pack(x, y); /// /// Initializes a new instance of the struct. /// /// A vector containing the initial values for the components. - public HalfVector2(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } + public HalfVector2(Vector2 vector) => this.PackedValue = Pack(vector.X, vector.Y); /// public uint PackedValue { get; set; } @@ -50,57 +33,30 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfVector2 left, HalfVector2 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfVector2 left, HalfVector2 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfVector2 left, HalfVector2 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - Vector2 vector; - vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue); - vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)); - return vector; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; @@ -109,7 +65,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -119,14 +75,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { var vector = this.ToVector2(); @@ -134,156 +87,74 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override string ToString() + /// + /// Expands the packed representation into a . + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() { - return this.ToVector2().ToString(); + Vector2 vector; + vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue); + vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)); + return vector; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); + public override bool Equals(object obj) => obj is HalfVector2 other && this.Equals(other); /// - public override bool Equals(object obj) - { - return obj is HalfVector2 other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfVector2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfVector2 other) + public override string ToString() { - return this.PackedValue.Equals(other.PackedValue); + var vector = this.ToVector2(); + return $"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(float x, float y) { uint num2 = HalfTypeHelper.Pack(x); uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10); return num2 | num; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 9bdae99abe..45d93efc09 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -15,16 +14,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct HalfVector4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - /// /// Initializes a new instance of the struct. /// @@ -33,64 +22,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public HalfVector4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - var vector = new Vector4(x, y, z, w); - this.PackedValue = Pack(ref vector); } /// /// Initializes a new instance of the struct. /// /// A vector containing the initial values for the components - public HalfVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public ulong PackedValue { get; set; } /// - /// Compares two objects for equality. + /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfVector4 left, HalfVector4 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfVector4 left, HalfVector4 right) => left.Equals(right); /// - /// Compares two objects for equality. + /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfVector4 left, HalfVector4 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 2F; @@ -99,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -109,14 +80,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -127,140 +95,61 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override string ToString() - { - return this.ToVector4().ToString(); - } + public override bool Equals(object obj) => obj is HalfVector4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfVector4 other) => this.PackedValue.Equals(other.PackedValue); /// - public override bool Equals(object obj) + public override string ToString() { - return obj is HalfVector4 other && this.Equals(other); + var vector = this.ToVector4(); + return $"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfVector4 other) - { - return this.PackedValue.Equals(other.PackedValue); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// /// Packs a into a . /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static ulong Pack(ref Vector4 vector) { ulong num4 = HalfTypeHelper.Pack(vector.X); @@ -269,15 +158,5 @@ namespace SixLabors.ImageSharp.PixelFormats ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30; return num4 | num3 | num2 | num1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 382c8541d6..a3017501ce 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -28,12 +28,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public interface IPixel { - /// - /// Sets the packed representation from a . - /// - /// The vector to create the packed representation from. - void PackFromVector4(Vector4 vector); - /// /// Sets the packed representation from a scaled . /// @@ -48,6 +42,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The . Vector4 ToScaledVector4(); + /// + /// Sets the packed representation from a . + /// + /// The vector to create the packed representation from. + void PackFromVector4(Vector4 vector); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. @@ -55,24 +55,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// The . Vector4 ToVector4(); - /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgba32(Rgba32 source); - - /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgb48(Rgb48 source); - - /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgba64(Rgba64 source); - /// /// Packs the pixel from an value. /// @@ -86,69 +68,39 @@ namespace SixLabors.ImageSharp.PixelFormats void PackFromBgra32(Bgra32 source); /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToRgb24(ref Rgb24 dest); - - /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToRgba32(ref Rgba32 dest); - - /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToRgb48(ref Rgb48 dest); - - /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToRgba64(ref Rgba64 dest); - - /// - /// Converts the pixel to format. - /// - /// The destination pixel to write to - void ToArgb32(ref Argb32 dest); - - /// - /// Converts the pixel to format. + /// Packs the Pixel from an value. /// - /// The destination pixel to write to - void ToBgr24(ref Bgr24 dest); + /// The value. + void PackFromGray8(Gray8 source); /// - /// Converts the pixel to format. + /// Packs the Pixel from an value. /// - /// The destination pixel to write to - void ToBgra32(ref Bgra32 dest); + /// The value. + void PackFromGray16(Gray16 source); /// - /// Packs the Pixel from an value. + /// Packs the pixel from an value. /// - /// The value. - void PackFromGray8(Gray8 source); + /// The value. + void PackFromRgba32(Rgba32 source); /// - /// Converts the pixel to format. + /// Expands the packed representation into an . /// - /// The destination pixel to write to. - void ToGray8(ref Gray8 dest); + /// The . + Rgba32 ToRgba32(); /// - /// Packs the Pixel from an value. + /// Packs the pixel from an value. /// - /// The value. - void PackFromGray16(Gray16 source); + /// The value. + void PackFromRgb48(Rgb48 source); /// - /// Converts the pixel tgo value. + /// Packs the pixel from an value. /// - /// The destination pixel to write to. - void ToGray16(ref Gray16 dest); + /// The value. + void PackFromRgba64(Rgba64 source); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index cd9fa65fbe..86b5280902 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedByte2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); + private static readonly Vector2 Half = new Vector2(127); + private static readonly Vector2 MinusOne = new Vector2(-1F); /// /// Initializes a new instance of the struct. /// - /// The vector containing the component values. - public NormalizedByte2(Vector2 vector) + /// The x-component. + /// The y-component. + public NormalizedByte2(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(vector.X, vector.Y); } /// /// Initializes a new instance of the struct. /// - /// The x-component. - /// The y-component. - public NormalizedByte2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + /// The vector containing the component values. + public NormalizedByte2(Vector2 vector) => this.PackedValue = Pack(vector); /// public ushort PackedValue { get; set; } @@ -55,66 +40,39 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2( - (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, - (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); + this.PackedValue = Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -124,188 +82,89 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() { - return obj is NormalizedByte2 other && this.Equals(other); + return new Vector2( + (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, + (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedByte2 other) - { - return this.PackedValue == other.PackedValue; - } + public override bool Equals(object obj) => obj is NormalizedByte2 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedByte2 other) => this.PackedValue.Equals(other.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector2(); + return $"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(Vector2 vector) { - int byte2 = ((ushort)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; - int byte1 = ((ushort)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; + vector = Vector2.Clamp(vector, MinusOne, Vector2.One) * Half; - return (ushort)(byte2 | byte1); - } + int byte2 = ((ushort)Math.Round(vector.X) & 0xFF) << 0; + int byte1 = ((ushort)Math.Round(vector.Y) & 0xFF) << 8; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; + return (ushort)(byte2 | byte1); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index 9b53adeccf..b538e4a449 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedByte4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedByte4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + private static readonly Vector4 MinusOne = new Vector4(-1F); /// /// Initializes a new instance of the struct. @@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public NormalizedByte4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(ref vector); + /// public uint PackedValue { get; set; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 2F; @@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -131,178 +99,66 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is NormalizedByte4 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is NormalizedByte4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedByte4 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedByte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector4(); + return $"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(ref Vector4 vector) { - uint byte4 = ((uint)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; - uint byte3 = ((uint)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; - uint byte2 = ((uint)Math.Round(z.Clamp(-1F, 1F) * 127F) & 0xFF) << 16; - uint byte1 = ((uint)Math.Round(w.Clamp(-1F, 1F) * 127F) & 0xFF) << 24; + vector = Vector4.Clamp(vector, MinusOne, Vector4.One) * Half; - return byte4 | byte3 | byte2 | byte1; - } + uint byte4 = ((uint)Math.Round(vector.X) & 0xFF) << 0; + uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 8; + uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 16; + uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 24; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; + return byte4 | byte3 | byte2 | byte1; } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 3319a10927..6135826f48 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedShort2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); + private static readonly Vector2 Max = new Vector2(0x7FFF); + private static readonly Vector2 Min = Vector2.Negate(Max); /// /// Initializes a new instance of the struct. /// - /// The vector containing the component values. - public NormalizedShort2(Vector2 vector) + /// The x-component. + /// The y-component. + public NormalizedShort2(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(vector.X, vector.Y); } /// /// Initializes a new instance of the struct. /// - /// The x-component. - /// The y-component. - public NormalizedShort2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + /// The vector containing the component values. + public NormalizedShort2(Vector2 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -55,53 +40,39 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); + this.PackedValue = Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -111,146 +82,55 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0, 1); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector2 ToVector2() { const float MaxVal = 0x7FFF; @@ -261,61 +141,34 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - public override bool Equals(object obj) - { - return obj is NormalizedShort2 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is NormalizedShort2 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedShort2 other) - { - return this.PackedValue.Equals(other.PackedValue); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedShort2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector2(); + return $"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) { - const float MaxPos = 0x7FFF; - const float MinNeg = -MaxPos; + vector *= Max; + vector = Vector2.Clamp(vector, Min, Max); - // Clamp the value between min and max values // Round rather than truncate. - uint word2 = (uint)((int)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF); - uint word1 = (uint)(((int)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10); + uint word2 = (uint)((int)MathF.Round(vector.X) & 0xFFFF); + uint word1 = (uint)(((int)MathF.Round(vector.Y) & 0xFFFF) << 0x10); return word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 7a74a44349..9717829a24 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct NormalizedShort4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedShort4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + private static readonly Vector4 Max = new Vector4(0x7FFF); + private static readonly Vector4 Min = Vector4.Negate(Max); /// /// Initializes a new instance of the struct. @@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public NormalizedShort4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(ref vector); + /// public ulong PackedValue { get; set; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) - { - return left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) - { - return !left.Equals(right); - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 2F; @@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { const float MaxVal = 0x7FFF; @@ -133,185 +101,68 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is NormalizedShort4 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is NormalizedShort4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedShort4 other) - { - return this.PackedValue.Equals(other.PackedValue); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedShort4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("X"); + var vector = this.ToVector4(); + return $"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ulong Pack(ref Vector4 vector) { - const float MaxPos = 0x7FFF; - const float MinNeg = -MaxPos; + vector *= Max; + vector = Vector4.Clamp(vector, Min, Max); - // Clamp the value between min and max values - ulong word4 = ((ulong)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00; - ulong word3 = ((ulong)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10; - ulong word2 = ((ulong)MathF.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20; - ulong word1 = ((ulong)MathF.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30; + // Round rather than truncate. + ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00; + ulong word3 = ((ulong)MathF.Round(vector.Y) & 0xFFFF) << 0x10; + ulong word2 = ((ulong)MathF.Round(vector.Z) & 0xFFFF) << 0x20; + ulong word1 = ((ulong)MathF.Round(vector.W) & 0xFFFF) << 0x30; return word4 | word3 | word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index e4bed1275b..3375a9753b 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -15,24 +15,23 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Rg32 : IPixel, IPackedVector { + private static readonly Vector2 Max = new Vector2(ushort.MaxValue); + /// /// Initializes a new instance of the struct. /// /// The x-component /// The y-component public Rg32(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(x, y); } /// /// Initializes a new instance of the struct. /// /// The vector containing the component values. - public Rg32(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } + public Rg32(Vector2 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -40,230 +39,111 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rg32 left, Rg32 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rg32 left, Rg32 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rg32 left, Rg32 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2( - (this.PackedValue & 0xFFFF) / 65535F, - ((this.PackedValue >> 16) & 0xFFFF) / 65535F); - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() => new Vector2(this.PackedValue & 0xFFFF, (this.PackedValue >> 16) & 0xFFFF) / Max; /// - public override bool Equals(object obj) - { - return obj is Rg32 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Rg32 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rg32 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rg32 other) => this.PackedValue.Equals(other.PackedValue); /// public override string ToString() { - return this.ToVector2().ToString(); + var vector = this.ToVector2(); + return $"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) { - return (uint)( - ((int)Math.Round(x.Clamp(0, 1) * 65535F) & 0xFFFF) | - (((int)Math.Round(y.Clamp(0, 1) * 65535F) & 0xFFFF) << 16)); + vector = Vector2.Clamp(vector, Vector2.Zero, Vector2.One) * Max; + return (uint)(((int)Math.Round(vector.X) & 0xFFFF) | (((int)Math.Round(vector.Y) & 0xFFFF) << 16)); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F; } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index 4c5aef5438..0b2c39ab5d 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -42,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb24(byte r, byte g, byte b) { this.R = r; @@ -50,39 +49,54 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = b; } + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgb24 left, Rgb24 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); + /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb24 other) - { - return this.R == other.R && this.G == other.G && this.B == other.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - public override bool Equals(object obj) - { - return obj is Rgb24 other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - return HashHelpers.Combine(hash, this.B.GetHashCode()); + Rgba32 rgba = default; + rgba.PackFromVector4(vector); + this.PackFromRgba32(rgba); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = Unsafe.As(ref source); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -91,7 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -100,74 +114,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) => dest = this; - - /// - public void ToRgba32(ref Rgba32 dest) - { - dest.Rgb = this; - dest.A = byte.MaxValue; - } - - /// - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - public void ToBgr24(ref Bgr24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { this.R = source.PackedValue; @@ -176,53 +123,57 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = Unsafe.As(ref source); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override bool Equals(object obj) => obj is Rgb24 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgb24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// - public override string ToString() + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() { - return $"({this.R},{this.G},{this.B})"; + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } + + /// + public override string ToString() => $"Rgb24({this.R}, {this.G}, {this.B})"; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 7784c49ffb..2ee1be6fe4 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.PixelFormats [StructLayout(LayoutKind.Sequential)] public struct Rgb48 : IPixel { - private const float Max = 65535F; + private const float Max = ushort.MaxValue; /// /// Gets or sets the red component. @@ -48,29 +48,6 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = b; } - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - public Rgb48(float r, float g, float b) - : this() - { - this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); - this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max); - this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components values. - public Rgb48(Vector3 vector) - : this(vector.X, vector.Y, vector.Z) - { - } - /// /// Compares two objects for equality. /// @@ -79,13 +56,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgb48 left, Rgb48 right) - { - return left.R == right.R - && left.G == right.G - && left.B == right.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgb48 left, Rgb48 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -95,40 +67,22 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgb48 left, Rgb48 right) - { - return left.R != right.R - || left.G != right.G - || left.B != right.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R / Max, this.G / Max, this.B / Max, 1); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; @@ -138,97 +92,43 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R / Max, this.G / Max, this.B / Max, 1F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this = source.Rgb; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { - var val = (ushort)(source.PackedValue * 255); - this.R = val; - this.G = val; - this.B = val; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) - { - dest.PackFromRgb48(this); + ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { this.R = source.PackedValue; @@ -236,49 +136,41 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.PackedValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - dest.PackFromRgb48(this); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this = source; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = this; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() { - dest.Rgb = this; - dest.A = ushort.MaxValue; + byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + return new Rgba32(r, g, b, byte.MaxValue); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this = source; + /// - public override bool Equals(object obj) - { - return obj is Rgb48 rgb48 && this.Equals(rgb48); - } + public override bool Equals(object obj) => obj is Rgb48 rgb48 && this.Equals(rgb48); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb48 other) - { - return this.R == other.R - && this.G == other.G - && this.B == other.B; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgb48 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// - public override string ToString() => this.ToVector4().ToString(); + public override string ToString() => $"Rgb48({this.R}, {this.G}, {this.B})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() { return HashHelpers.Combine( diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 6dd5f7b544..8bcf34f309 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -16,6 +16,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Rgba1010102 : IPixel, IPackedVector { + private static readonly Vector4 Multiplier = new Vector4(1023F, 1023F, 1023F, 3F); + /// /// Initializes a new instance of the struct. /// @@ -24,18 +26,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component /// The w-component public Rgba1010102(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } /// /// Initializes a new instance of the struct. /// /// The vector containing the component values. - public Rgba1010102(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(ref vector); /// public uint PackedValue { get; set; } @@ -43,222 +42,107 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba1010102 left, Rgba1010102 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba1010102 left, Rgba1010102 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba1010102 left, Rgba1010102 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4( - ((this.PackedValue >> 0) & 0x03FF) / 1023F, - ((this.PackedValue >> 10) & 0x03FF) / 1023F, - ((this.PackedValue >> 20) & 0x03FF) / 1023F, - ((this.PackedValue >> 30) & 0x03) / 3F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); + return new Vector4( + (this.PackedValue >> 0) & 0x03FF, + (this.PackedValue >> 10) & 0x03FF, + (this.PackedValue >> 20) & 0x03FF, + (this.PackedValue >> 30) & 0x03) / Multiplier; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Rgba1010102 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Rgba1010102 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba1010102 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue; /// - public override string ToString() - { - return this.ToVector4().ToString(); - } + public override string ToString() => this.ToVector4().ToString(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(ref Vector4 vector) { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier; + return (uint)( - (((int)Math.Round(x.Clamp(0, 1) * 1023F) & 0x03FF) << 0) | - (((int)Math.Round(y.Clamp(0, 1) * 1023F) & 0x03FF) << 10) | - (((int)Math.Round(z.Clamp(0, 1) * 1023F) & 0x03FF) << 20) | - (((int)Math.Round(w.Clamp(0, 1) * 3F) & 0x03) << 30)); + (((int)Math.Round(vector.X) & 0x03FF) << 0) + | (((int)Math.Round(vector.Y) & 0x03FF) << 10) + | (((int)Math.Round(vector.Z) & 0x03FF) << 20) + | (((int)Math.Round(vector.W) & 0x03) << 30)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index aab9fad928..e92da02668 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(byte r, byte g, byte b) { this.R = r; @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(byte r, byte g, byte b, byte a) { this.R = r; @@ -109,12 +109,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(float r, float g, float b, float a = 1) - : this() - { - this.Pack(r, g, b, a); - } + : this() => this.Pack(r, g, b, a); /// /// Initializes a new instance of the struct. @@ -122,12 +119,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(Vector3 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -135,12 +129,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(Vector4 vector) - : this() - { - this = PackNew(ref vector); - } + : this() => this = PackNew(ref vector); /// /// Initializes a new instance of the struct. @@ -148,22 +139,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The packed value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(uint packed) - : this() - { - this.Rgba = packed; - } + : this() => this.Rgba = packed; /// /// Gets or sets the packed representation of the Rgba32 struct. /// public uint Rgba { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -172,10 +160,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Rgb24 Rgb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -184,10 +172,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Bgr24 Bgr { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => new Bgr24(this.R, this.G, this.B); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set { this.R = value.R; @@ -199,30 +187,23 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint PackedValue { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => this.Rgba; - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => this.Rgba = value; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba32 left, Rgba32 right) - { - return left.Rgba == right.Rgba; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba32 left, Rgba32 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -232,11 +213,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba32 left, Rgba32 right) - { - return left.Rgba != right.Rgba; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba32 left, Rgba32 right) => !left.Equals(right); /// /// Creates a new instance of the struct. @@ -248,23 +226,29 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The . /// - public static Rgba32 FromHex(string hex) - { - return ColorBuilder.FromHex(hex); - } + public static Rgba32 FromHex(string hex) => ColorBuilder.FromHex(hex); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = source; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + + /// + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { this.R = source.R; @@ -274,7 +258,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { this.R = source.R; @@ -283,213 +267,85 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } - /// - /// Converts the value of this instance to a hexadecimal string. - /// - /// A hexadecimal string representation of the value. - public string ToHex() - { - uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24); - return hexOrder.ToString("X8"); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest = Unsafe.As(ref this); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest = this; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; this.B = source.PackedValue; - this.A = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) - { - dest.PackFromRgba32(this); + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) { - var val = (byte)(((source.PackedValue * 255) + 32895) >> 16); - this.R = val; - this.G = val; - this.B = val; - this.A = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) - { - dest.PackFromRgba32(this); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } - - /// - /// Gets the value of this struct as . - /// Useful for changing the component order. - /// - /// A value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A); - - /// - /// Gets the value of this struct as . - /// Useful for changing the component order. - /// - /// A value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = source; - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => this; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) { - // Taken from libpng pngtran.c line: 2419 - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) + /// + /// Converts the value of this instance to a hexadecimal string. + /// + /// A hexadecimal string representation of the value. + public string ToHex() { - return obj is Rgba32 rgba32 && this.Equals(rgba32); + uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24); + return hexOrder.ToString("X8"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba32 other) - { - return this.Rgba == other.Rgba; - } + public override bool Equals(object obj) => obj is Rgba32 rgba32 && this.Equals(rgba32); /// - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba32 other) => this.Rgba.Equals(other.Rgba); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.Rgba.GetHashCode(); + public override string ToString() => $"Rgba32({this.R}, {this.G}, {this.B}, {this.A})"; - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.Rgba.GetHashCode(); /// /// Packs a into a color returning a new instance as a result. /// /// The vector containing the values to pack. /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Rgba32 PackNew(ref Vector4 vector) { vector *= MaxBytes; @@ -506,7 +362,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(float x, float y, float z, float w) { var value = new Vector4(x, y, z, w); @@ -517,10 +373,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector3 vector) { - var value = new Vector4(vector, 1); + var value = new Vector4(vector, 1F); this.Pack(ref value); } @@ -528,7 +384,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 5c3187856e..623f7051af 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.PixelFormats [StructLayout(LayoutKind.Sequential)] public struct Rgba64 : IPixel, IPackedVector { - private const float Max = 65535F; + private const float Max = ushort.MaxValue; /// /// Gets or sets the red component. @@ -47,7 +47,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// The blue component. /// The alpha component. public Rgba64(ushort r, ushort g, ushort b, ushort a) - : this() { this.R = r; this.G = g; @@ -55,126 +54,63 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = a; } - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - public Rgba64(float r, float g, float b, float a) - : this() - { - this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); - this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max); - this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max); - this.A = (ushort)MathF.Round(a.Clamp(0, 1) * Max); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components values. - public Rgba64(Vector4 vector) - : this(vector.X, vector.Y, vector.Z, vector.W) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The packed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba64(ulong packed) - : this() - { - this.PackedValue = packed; - } - /// /// Gets or sets the RGB components of this struct as /// public Rgb48 Rgb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } /// public ulong PackedValue { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba64 left, Rgba64 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba64 left, Rgba64 right) => left.PackedValue == right.PackedValue; /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba64 left, Rgba64 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / Max; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; @@ -185,145 +121,95 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) { - this.PackFromVector4(source.ToVector4()); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this = source; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - // Taken from libpng pngtran.c line: 2419 - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray8(Gray8 source) { - this.Rgb = source; + ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; this.A = ushort.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = this.Rgb; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest = this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromGray16(Gray16 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = ushort.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); + byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + byte a = ImageMaths.DownScaleFrom16BitTo8Bit(this.A); + return new Rgba32(r, g, b, a); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray8(Gray8 source) - { - ushort x = (ushort)(source.PackedValue * 255); - this.R = x; - this.G = x; - this.B = x; - this.A = ushort.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromGray16(Gray16 source) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; + this.Rgb = source; this.A = ushort.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba64(Rgba64 source) => this = source; /// - public override bool Equals(object obj) - { - return obj is Rgba64 rgba64 && this.Equals(rgba64); - } + public override bool Equals(object obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba64 other) - { - return this.PackedValue == other.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba64 other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + public override string ToString() => $"Rgba64({this.R}, {this.G}, {this.B}, {this.A})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index 3ab45a66ef..5ca0ce406f 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -1,9 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.PixelFormats { @@ -18,36 +18,32 @@ namespace SixLabors.ImageSharp.PixelFormats /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// as it avoids the need to create new values for modification operations. /// + [StructLayout(LayoutKind.Sequential)] public partial struct RgbaVector : IPixel { /// - /// The maximum byte value. + /// Gets or sets the red component. /// - private static readonly Vector4 MaxBytes = new Vector4(255); + public float R; /// - /// The half vector value. + /// Gets or sets the green component. /// - private static readonly Vector4 Half = new Vector4(0.5F); + public float G; /// - /// The backing vector for SIMD support. + /// Gets or sets the blue component. /// - private Vector4 backingVector; + public float B; /// - /// Initializes a new instance of the struct. + /// Gets or sets the alpha component. /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(byte r, byte g, byte b, byte a = 255) - : this() - { - this.backingVector = new Vector4(r, g, b, a) / MaxBytes; - } + public float A; + + private const float MaxBytes = byte.MaxValue; + private static readonly Vector4 Max = new Vector4(MaxBytes); + private static readonly Vector4 Half = new Vector4(0.5F); /// /// Initializes a new instance of the struct. @@ -56,128 +52,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public RgbaVector(float r, float g, float b, float a = 1) - : this() - { - this.backingVector = new Vector4(r, g, b, a); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(Vector3 vector) - : this() - { - this.backingVector = new Vector4(vector, 1); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(Vector4 vector) - : this() - { - this.backingVector = vector; - } - - /// - /// Gets or sets the red component. - /// - public float R - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.X; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.X = value; - } - } - - /// - /// Gets or sets the green component. - /// - public float G - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.Y; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.Y = value; - } - } - - /// - /// Gets or sets the blue component. - /// - public float B { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.Z; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.Z = value; - } - } - - /// - /// Gets or sets the alpha component. - /// - public float A - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.W; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.W = value; - } + this.R = r; + this.G = g; + this.B = b; + this.A = a; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(RgbaVector left, RgbaVector right) - { - return left.backingVector == right.backingVector; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(RgbaVector left, RgbaVector right) => left.Equals(right); /// /// Compares two objects for equality. @@ -187,11 +80,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(RgbaVector left, RgbaVector right) - { - return left.backingVector != right.backingVector; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(RgbaVector left, RgbaVector right) => !left.Equals(right); /// /// Creates a new instance of the struct. @@ -203,190 +93,103 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The . /// - public static RgbaVector FromHex(string hex) - { - return ColorBuilder.FromHex(hex); - } + public static RgbaVector FromHex(string hex) => ColorBuilder.FromHex(hex); /// - public PixelOperations CreatePixelOperations() => new RgbaVector.PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.backingVector = source.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.backingVector = source.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.backingVector = source.ToVector4(); - } - - /// - /// Converts the value of this instance to a hexadecimal string. - /// - /// A hexadecimal string representation of the value. - public string ToHex() - { - // Hex is RRGGBBAA - Vector4 vector = this.backingVector * MaxBytes; - vector += Half; - uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24); - return hexOrder.ToString("X8"); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + this.R = vector.X; + this.G = vector.Y; + this.B = vector.Z; + this.A = vector.W; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) + /// + /// Converts the value of this instance to a hexadecimal string. + /// + /// A hexadecimal string representation of the value. + public string ToHex() { - this.backingVector = vector; + // Hex is RRGGBBAA + Vector4 vector = this.ToVector4() * Max; + vector += Half; + uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24); + return hexOrder.ToString("X8"); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return this.backingVector; - } + public override bool Equals(object obj) => obj is RgbaVector other && this.Equals(other); /// - public override bool Equals(object obj) - { - return obj is RgbaVector other && this.Equals(other); - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(RgbaVector other) => + this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B) + && this.A.Equals(other.A); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(RgbaVector other) - { - return this.backingVector == other.backingVector; - } - - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. public override string ToString() { - return this.ToVector4().ToString(); + var vector = this.ToVector4(); + return $"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"; } /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.A.GetHashCode()); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 331c5fb208..24430a5d9f 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -15,39 +15,30 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Short2 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector2 MaxBytes = new Vector2(255); + // Largest two byte positive number 0xFFFF >> 1; + private const float MaxPos = 0x7FFF; - /// - /// The half the maximum byte value. - /// - private static readonly Vector2 Half = new Vector2(127); + // Two's complement + private const float MinNeg = ~(int)MaxPos; - /// - /// The vector value used for rounding. - /// - private static readonly Vector2 Round = new Vector2(.5F); + private static readonly Vector2 Max = new Vector2(MaxPos); + private static readonly Vector2 Min = new Vector2(MinNeg); /// /// Initializes a new instance of the struct. /// - /// The vector containing the component values. - public Short2(Vector2 vector) + /// The x-component. + /// The y-component. + public Short2(float x, float y) + : this(new Vector2(x, y)) { - this.PackedValue = Pack(vector.X, vector.Y); } /// /// Initializes a new instance of the struct. /// - /// The x-component. - /// The y-component. - public Short2(float x, float y) - { - this.PackedValue = Pack(x, y); - } + /// The vector containing the component values. + public Short2(Vector2 vector) => this.PackedValue = Pack(vector); /// public uint PackedValue { get; set; } @@ -55,53 +46,39 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// - /// True if the parameter is equal to the parameter; otherwise, false. + /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Short2 left, Short2 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Short2 left, Short2 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Short2 left, Short2 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F; scaled -= new Vector2(32767F); - this.PackedValue = Pack(scaled.X, scaled.Y); + this.PackedValue = Pack(scaled); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector2(); @@ -111,198 +88,83 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() => new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); /// - public override bool Equals(object obj) - { - return obj is Short2 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Short2 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Short2 other) - { - return this == other; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Short2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); /// public override string ToString() { - return this.PackedValue.ToString("x8"); + var vector = this.ToVector2(); + return $"Short2({vector.X:#0.##}, {vector.Y:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) { - // Largest two byte positive number 0xFFFF >> 1; - const float MaxPos = 0x7FFF; - const float MinNeg = ~(int)MaxPos; - - // Clamp the value between min and max values - uint word2 = (uint)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF; - uint word1 = ((uint)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; + vector = Vector2.Clamp(vector, Min, Max); + uint word2 = (uint)Math.Round(vector.X) & 0xFFFF; + uint word1 = ((uint)Math.Round(vector.Y) & 0xFFFF) << 0x10; return word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector2 ToByteScaledVector2() - { - var vector = this.ToVector2(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - return vector; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 4a3d89ad8b..4925137470 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -15,29 +15,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct Short4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); + // Largest two byte positive number 0xFFFF >> 1; + private const float MaxPos = 0x7FFF; - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); + // Two's complement + private const float MinNeg = ~(int)MaxPos; - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// A vector containing the initial values for the components. - public Short4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + private static readonly Vector4 Max = new Vector4(MaxPos); + private static readonly Vector4 Min = new Vector4(MinNeg); /// /// Initializes a new instance of the struct. @@ -47,54 +32,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// The z-component. /// The w-component. public Short4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - this.PackedValue = Pack(x, y, z, w); } + /// + /// Initializes a new instance of the struct. + /// + /// A vector containing the initial values for the components. + public Short4(Vector4 vector) => this.PackedValue = Pack(ref vector); + /// public ulong PackedValue { get; set; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Short4 left, Short4 right) - { - return left.PackedValue == right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Short4 left, Short4 right) => left.Equals(right); /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Short4 left, Short4 right) - { - return left.PackedValue != right.PackedValue; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromScaledVector4(Vector4 vector) { vector *= 65534F; @@ -103,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToScaledVector4() { var scaled = this.ToVector4(); @@ -113,14 +90,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ToVector4() { return new Vector4( @@ -131,184 +105,70 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray8(ref Gray8 dest) => dest.PackFromVector4(this.ToVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToGray16(ref Gray16 dest) => dest.PackFromVector4(this.ToVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - /// - public override bool Equals(object obj) - { - return obj is Short4 other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Short4 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Short4 other) - { - return this == other; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Short4 other) => this.PackedValue.Equals(other); /// /// Gets the hash code for the current instance. /// /// Hash code for the instance. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - /// - /// Returns a string representation of the current instance. - /// - /// String that represents the object. + /// public override string ToString() { - return this.PackedValue.ToString("x16"); + var vector = this.ToVector4(); + return $"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; } - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(float x, float y, float z, float w) + [MethodImpl(InliningOptions.ShortMethod)] + private static ulong Pack(ref Vector4 vector) { - // Largest two byte positive number 0xFFFF >> 1; - const float MaxPos = 0x7FFF; - - // Two's complement - const float MinNeg = ~(int)MaxPos; + vector = Vector4.Clamp(vector, Min, Max); // Clamp the value between min and max values - ulong word4 = ((ulong)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x00; - ulong word3 = ((ulong)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; - ulong word2 = ((ulong)Math.Round(z.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x20; - ulong word1 = ((ulong)Math.Round(w.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x30; + ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00; + ulong word3 = ((ulong)Math.Round(vector.Y) & 0xFFFF) << 0x10; + ulong word2 = ((ulong)Math.Round(vector.Z) & 0xFFFF) << 0x20; + ulong word1 = ((ulong)Math.Round(vector.W) & 0xFFFF) << 0x30; return word4 | word3 | word2 | word1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - return Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs index 5041dcf5ac..b338ff446e 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs @@ -76,8 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; - Rgba32 rgba = default; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -89,10 +88,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -106,8 +105,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs index 048af82619..0b28a1574b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs @@ -56,7 +56,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -68,10 +67,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -85,8 +84,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 60754b3bf2..03b7f73e94 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); TPixel upper = this.UpperColor; TPixel lower = this.LowerColor; @@ -83,17 +83,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization for (int y = rows.Min; y < rows.Max; y++) { Span row = source.GetPixelRowSpan(y); - Rgba32 rgba = default; for (int x = startX; x < endX; x++) { ref TPixel color = ref row[x]; - color.ToRgba32(ref rgba); + var rgba = color.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly - ? rgba.A - : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); color = luminance >= threshold ? upper : lower; } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs index 8e2b2a5a82..b60322799a 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering @@ -64,8 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; - Rgba32 rgba = default; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -78,10 +76,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -103,8 +101,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs index b5e2eebc2b..149c7170ac 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering @@ -32,10 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// The ordered ditherer. /// The palette to select substitute colors from. public OrderedDitherPaletteProcessor(IOrderedDither dither, TPixel[] palette) - : base(palette) - { - this.Dither = dither ?? throw new ArgumentNullException(nameof(dither)); - } + : base(palette) => this.Dither = dither ?? throw new ArgumentNullException(nameof(dither)); /// /// Gets the ditherer. @@ -45,7 +41,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -58,10 +53,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - sourcePixel.ToRgba32(ref rgba); + var rgba = sourcePixel.ToRgba32(); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -83,8 +78,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + rgba = sourcePixel.ToRgba32(); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 39546d63f7..552aa8af82 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -73,14 +73,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); // And loop through each column - Rgba32 rgba = default; for (int x = 0; x < width; x++) { ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); - pixel.ToRgba32(ref rgba); // Add the color to the Octree - this.octree.AddColor(ref pixel, ref rgba); + this.octree.AddColor(ref pixel); } } } @@ -97,9 +95,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // pass of the algorithm by avoiding transforming rows of identical color. TPixel sourcePixel = source[0, 0]; TPixel previousPixel = sourcePixel; - Rgba32 rgba = default; this.transparentIndex = this.GetTransparentIndex(); - byte pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba); + byte pixelValue = this.QuantizePixel(ref sourcePixel); TPixel transformedPixel = palette[pixelValue]; for (int y = 0; y < height; y++) @@ -117,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (!previousPixel.Equals(sourcePixel)) { // Quantize the pixel - pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba); + pixelValue = this.QuantizePixel(ref sourcePixel); // And setup the previous pointer previousPixel = sourcePixel; @@ -146,10 +143,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Process the pixel in the second pass of the algorithm. /// /// The pixel to quantize. - /// The color to compare against. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte QuantizePixel(ref TPixel pixel, ref Rgba32 rgba) + private byte QuantizePixel(ref TPixel pixel) { if (this.Dither) { @@ -158,13 +154,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return this.GetClosestPixel(ref pixel); } - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); if (rgba.Equals(default)) { return this.transparentIndex; } - return (byte)this.octree.GetPaletteIndex(ref pixel, ref rgba); + return (byte)this.octree.GetPaletteIndex(ref pixel); } /// @@ -239,8 +235,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Add a given color value to the Octree /// /// The pixel data. - /// The color. - public void AddColor(ref TPixel pixel, ref Rgba32 rgba) + public void AddColor(ref TPixel pixel) { // Check if this request is for the same color as the last if (this.previousColor.Equals(pixel)) @@ -250,18 +245,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (this.previousNode is null) { this.previousColor = pixel; - this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba); + this.root.AddColor(ref pixel, this.maxColorBits, 0, this); } else { // Just update the previous node - this.previousNode.Increment(ref pixel, ref rgba); + this.previousNode.Increment(ref pixel); } } else { this.previousColor = pixel; - this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba); + this.root.AddColor(ref pixel, this.maxColorBits, 0, this); } } @@ -294,12 +289,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Get the palette index for the passed color /// /// The pixel data. - /// The color to map to. /// /// The . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetPaletteIndex(ref TPixel pixel, ref Rgba32 rgba) => this.root.GetPaletteIndex(ref pixel, 0, ref rgba); + public int GetPaletteIndex(ref TPixel pixel) => this.root.GetPaletteIndex(ref pixel, 0); /// /// Keep track of the previous node that was quantized @@ -426,13 +420,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The number of significant color bits /// The level in the tree /// The tree to which this node belongs - /// The color to map to. - public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree, ref Rgba32 rgba) + public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree) { // Update the color information if this is a leaf if (this.leaf) { - this.Increment(ref pixel, ref rgba); + this.Increment(ref pixel); // Setup the previous node octree.TrackPrevious(this); @@ -441,7 +434,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { // Go to the next level down in the tree int shift = 7 - level; - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); int index = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -456,7 +449,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // Add the color to the child node - child.AddColor(ref pixel, colorBits, level + 1, octree, ref rgba); + child.AddColor(ref pixel, colorBits, level + 1, octree); } } @@ -525,19 +518,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The pixel data. /// The level. - /// The color to map to. /// /// The representing the index of the pixel in the palette. /// [MethodImpl(MethodImplOptions.NoInlining)] - public int GetPaletteIndex(ref TPixel pixel, int level, ref Rgba32 rgba) + public int GetPaletteIndex(ref TPixel pixel, int level) { int index = this.paletteIndex; if (!this.leaf) { int shift = 7 - level; - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); int pixelIndex = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -546,7 +538,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization OctreeNode child = this.children[pixelIndex]; if (child != null) { - index = child.GetPaletteIndex(ref pixel, level + 1, ref rgba); + index = child.GetPaletteIndex(ref pixel, level + 1); } else { @@ -561,11 +553,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Increment the pixel count and add to the color information /// /// The pixel to add. - /// The color to map to. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Increment(ref TPixel pixel, ref Rgba32 rgba) + public void Increment(ref TPixel pixel) { - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); this.pixelCount++; this.red += rgba.R; this.green += rgba.G; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 13bc057da8..f3b5da3202 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -442,33 +442,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Build up the 3-D color histogram // Loop through each row - for (int y = 0; y < height; y++) + using (IMemoryOwner rgbaBuffer = source.MemoryAllocator.Allocate(source.Width)) { - Span row = source.GetPixelRowSpan(y); - ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); - - // And loop through each column - Rgba32 rgba = default; - for (int x = 0; x < width; x++) + for (int y = 0; y < height; y++) { - ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); - pixel.ToRgba32(ref rgba); + Span row = source.GetPixelRowSpan(y); + Span rgbaSpan = rgbaBuffer.GetSpan(); + PixelOperations.Instance.ToRgba32(row, rgbaSpan, source.Width); + ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan); + + // And loop through each column + for (int x = 0; x < width; x++) + { + ref Rgba32 rgba = ref Unsafe.Add(ref scanBaseRef, x); - int r = rgba.R >> (8 - IndexBits); - int g = rgba.G >> (8 - IndexBits); - int b = rgba.B >> (8 - IndexBits); - int a = rgba.A >> (8 - IndexAlphaBits); + int r = rgba.R >> (8 - IndexBits); + int g = rgba.G >> (8 - IndexBits); + int b = rgba.B >> (8 - IndexBits); + int a = rgba.A >> (8 - IndexAlphaBits); - int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); + int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); - vwtSpan[index]++; - vmrSpan[index] += rgba.R; - vmgSpan[index] += rgba.G; - vmbSpan[index] += rgba.B; - vmaSpan[index] += rgba.A; + vwtSpan[index]++; + vmrSpan[index] += rgba.R; + vmgSpan[index] += rgba.G; + vmbSpan[index] += rgba.B; + vmaSpan[index] += rgba.A; - var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); - m2Span[index] += Vector4.Dot(vector, vector); + var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); + m2Span[index] += Vector4.Dot(vector, vector); + } } } } @@ -876,8 +879,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // Expected order r->g->b->a - Rgba32 rgba = default; - pixel.ToRgba32(ref rgba); + var rgba = pixel.ToRgba32(); int r = rgba.R >> (8 - IndexBits); int g = rgba.G >> (8 - IndexBits); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs index 4e9c6d10a6..f96023f000 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs @@ -4,10 +4,7 @@ // ReSharper disable InconsistentNaming using System.Buffers; -using System; - using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -38,35 +35,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void PerElement() - { - Span s = this.source.GetSpan(); - Span d = this.destination.GetSpan(); - - var rgb = default(Rgb24); - - for (int i = 0; i < this.Count; i++) - { - TPixel c = s[i]; - int i3 = i * 3; - c.ToRgb24(ref rgb); - d[i3] = rgb.R; - d[i3 + 1] = rgb.G; - d[i3 + 2] = rgb.B; - } - } + public void CommonBulk() => new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); [Benchmark] - public void CommonBulk() - { - new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void OptimizedBulk() => PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } public class ToXyz_Rgba32 : ToXyz diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs index 8166c8f465..740287e85a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -42,13 +42,11 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); - var rgba = default(Rgba32); - for (int i = 0; i < this.Count; i++) { TPixel c = s[i]; int i4 = i * 4; - c.ToRgba32(ref rgba); + var rgba = c.ToRgba32(); d[i4] = rgba.R; d[i4 + 1] = rgba.G; d[i4 + 2] = rgba.B; @@ -57,16 +55,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void CommonBulk() - { - new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void CommonBulk() => new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void OptimizedBulk() => PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } public class ToXyzw_Rgba32 : ToXyzw diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 5ef8f0111f..5d163917cd 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,7 +2,7 @@ net462;net471;netcoreapp2.1 True - 7.3 + latest full portable True @@ -11,15 +11,15 @@ AnyCPU;x64;x86 - true + false - true + false - true + false diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 81fd59885a..4a0683fba7 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -48,46 +48,46 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal((uint)958796544, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(141, 90, 192)); + //new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(141, 90, 192)); - new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); + //new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); - new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(141, 90, 192)); + //new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(141, 90, 192)); - new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) + //new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(141, 90, 192, 39)); + //new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 - var r = default(NormalizedByte4); - r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - r.PackedValue = 0xff4af389; - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - r = default(NormalizedByte4); - r.PackFromArgb32(new Argb32(9, 115, 202, 127)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(9, 115, 202, 127)); - - r = default(NormalizedByte4); - r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); + //var r = default(NormalizedByte4); + //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + + //r.PackedValue = 0xff4af389; + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + + //r = default(NormalizedByte4); + //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); + + //r = default(NormalizedByte4); + //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue @@ -127,41 +127,41 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(0xa6674000d99a0ccd, new NormalizedShort4(x, y, z, w).PackedValue); Assert.Equal((ulong)4150390751449251866, new NormalizedShort4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(141, 90, 192)); + //new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(141, 90, 192)); - new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) + //new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(141, 90, 192)); + //new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(141, 90, 192)); - new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); + //new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); - new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(141, 90, 192, 39)); + //new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); - var r = default(NormalizedShort4); - r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + //var r = default(NormalizedShort4); + //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - r = default(NormalizedShort4); - r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); + //r = default(NormalizedShort4); + //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); - r = default(NormalizedShort4); - r.PackFromArgb32(new Argb32(9, 115, 202, 127)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(9, 115, 202, 127)); + //r = default(NormalizedShort4); + //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue @@ -212,41 +212,41 @@ namespace SixLabors.ImageSharp.Tests.Issues w = 193; Assert.Equal((ulong)0x00c173b7316d2d1b, new Short4(x, y, z, w).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new Short4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) + //new Short4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) - new Short4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); - new Short4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(172, 177, 243)); + //new Short4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(172, 177, 243)); - new Short4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); - new Short4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(172, 177, 243, 128)); - var r = default(Short4); - r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); + //var r = default(Short4); + //r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); - r = default(Short4); - r.PackFromBgra32(new Bgra32(20, 38, 0, 255)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); + //r = default(Short4); + //r.PackFromBgra32(new Bgra32(20, 38, 0, 255)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); - r = default(Short4); - r.PackFromArgb32(new Argb32(20, 38, 0, 255)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(20, 38, 0, 255)); + //r = default(Short4); + //r.PackFromArgb32(new Argb32(20, 38, 0, 255)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(20, 38, 0, 255)); } // Comparison helpers with small tolerance to allow for floating point rounding during computations. diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 9a29236dba..d5b7d9b2b2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -73,138 +73,138 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgb24() - { - // arrange - Rgb24 actual = default; - Alpha8 alpha = default; - var expected = new Rgb24(0, 0, 0); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgba32() - { - // arrange - Rgba32 actual = default; - Alpha8 alpha = default; - var expected = new Rgba32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToBgr24() - { - // arrange - Bgr24 actual = default; - Alpha8 alpha = default; - var expected = new Bgr24(0, 0, 0); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToBgra32() - { - // arrange - Bgra32 actual = default; - Alpha8 alpha = default; - var expected = new Bgra32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToArgb32() - { - // arrange - Alpha8 alpha = default; - Argb32 actual = default; - var expected = new Argb32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgba64() - { - // arrange - Alpha8 alpha = default; - Rgba64 actual = default; - var expected = new Rgba64(0, 0, 0, 65535); - Vector4 scaled = new Alpha8(1F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromRgb48_ToRgb48() - { - // arrange - var alpha = default(Alpha8); - var actual = default(Rgb48); - var expected = new Rgb48(0, 0, 0); - - // act - alpha.PackFromRgb48(expected); - alpha.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromRgba64_ToRgba64() - { - // arrange - var alpha = default(Alpha8); - var actual = default(Rgba64); - var expected = new Rgba64(0, 0, 0, 65535); - - // act - alpha.PackFromRgba64(expected); - alpha.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToRgb24() + //{ + // // arrange + // Rgb24 actual = default; + // Alpha8 alpha = default; + // var expected = new Rgb24(0, 0, 0); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToRgba32() + //{ + // // arrange + // Rgba32 actual = default; + // Alpha8 alpha = default; + // var expected = new Rgba32(0, 0, 0, 128); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToBgr24() + //{ + // // arrange + // Bgr24 actual = default; + // Alpha8 alpha = default; + // var expected = new Bgr24(0, 0, 0); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToBgra32() + //{ + // // arrange + // Bgra32 actual = default; + // Alpha8 alpha = default; + // var expected = new Bgra32(0, 0, 0, 128); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToArgb32() + //{ + // // arrange + // Alpha8 alpha = default; + // Argb32 actual = default; + // var expected = new Argb32(0, 0, 0, 128); + // Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromScaledVector4_ToRgba64() + //{ + // // arrange + // Alpha8 alpha = default; + // Rgba64 actual = default; + // var expected = new Rgba64(0, 0, 0, 65535); + // Vector4 scaled = new Alpha8(1F).ToScaledVector4(); + + // // act + // alpha.PackFromScaledVector4(scaled); + // alpha.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var alpha = default(Alpha8); + // var actual = default(Rgb48); + // var expected = new Rgb48(0, 0, 0); + + // // act + // alpha.PackFromRgb48(expected); + // alpha.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Alpha8_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var alpha = default(Alpha8); + // var actual = default(Rgba64); + // var expected = new Rgba64(0, 0, 0, 65535); + + // // act + // alpha.PackFromRgba64(expected); + // alpha.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 5817b5c329..53545f517a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -67,159 +67,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()); } - [Fact] - public void Argb32_ToRgb24() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(0x1a, 0, 0x80); - - // act - argb.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToRgba32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // act - argb.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToBgr24() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(0x1a, 0, 0x80); - - // act - argb.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToBgra32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - argb.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToArgb32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - argb.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgba32_ToRgba32() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromRgba32(expected); - argb.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromBgra32_ToBgra32() - { - // arrange - var argb = default(Argb32); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromBgra32(expected); - argb.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromArgb32_ToArgb32() - { - // arrange - var argb = default(Argb32); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromArgb32(expected); - argb.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgb48_ToRgb48() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - argb.PackFromRgb48(expected); - argb.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgba64_ToRgba64() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - argb.PackFromRgba64(expected); - argb.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Argb32_ToRgb24() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(0x1a, 0, 0x80); + + // // act + // argb.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_ToRgba32() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(0x1a, 0, 0x80, 0); + + // // act + // argb.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_ToBgr24() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(0x1a, 0, 0x80); + + // // act + // argb.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_ToBgra32() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(0x1a, 0, 0x80, 0); + + // // act + // argb.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_ToArgb32() + //{ + // // arrange + // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(0x1a, 0, 0x80, 0); + + // // act + // argb.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Rgba32); + // var expected = new Rgba32(0x1a, 0, 0x80, 0); + + // // act + // argb.PackFromRgba32(expected); + // argb.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Bgra32); + // var expected = new Bgra32(0x1a, 0, 0x80, 0); + + // // act + // argb.PackFromBgra32(expected); + // argb.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Argb32); + // var expected = new Argb32(0x1a, 0, 0x80, 0); + + // // act + // argb.PackFromArgb32(expected); + // argb.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // argb.PackFromRgb48(expected); + // argb.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Argb32_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var argb = default(Argb32); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // argb.PackFromRgba64(expected); + // argb.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 048a38380e..e742789e4d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -96,80 +96,80 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } - [Fact] - public void ToRgb24() - { - var rgb = new Bgr24(1, 2, 3); - var dest = default(Rgb24); - - rgb.ToRgb24(ref dest); - - Assert.Equal(new Rgb24(1, 2, 3), dest); - } - - [Fact] - public void ToRgba32() - { - var rgb = new Bgr24(1, 2, 3); - var rgba = default(Rgba32); - - rgb.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Bgr24(1, 2, 3); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Bgr24(1, 2, 3); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - } - - [Fact] - public void Bgr24_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgr24); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr24_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgr24); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void ToRgb24() + //{ + // var rgb = new Bgr24(1, 2, 3); + // var dest = default(Rgb24); + + // rgb.ToRgb24(ref dest); + + // Assert.Equal(new Rgb24(1, 2, 3), dest); + //} + + //[Fact] + //public void ToRgba32() + //{ + // var rgb = new Bgr24(1, 2, 3); + // var rgba = default(Rgba32); + + // rgb.ToRgba32(ref rgba); + + // Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); + //} + + //[Fact] + //public void ToBgr24() + //{ + // var rgb = new Bgr24(1, 2, 3); + // var bgr = default(Bgr24); + + // rgb.ToBgr24(ref bgr); + + // Assert.Equal(new Bgr24(1, 2, 3), bgr); + //} + + //[Fact] + //public void ToBgra32() + //{ + // var rgb = new Bgr24(1, 2, 3); + // var bgra = default(Bgra32); + + // rgb.ToBgra32(ref bgra); + + // Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); + //} + + //[Fact] + //public void Bgr24_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgr24); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr24_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgr24); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index b66cac9ca3..6954067a34 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -70,111 +70,111 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()); } - [Fact] - public void Bgr565_ToRgb24() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 132); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToRgba32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 132, 255); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToBgr24() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 132); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToBgra32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Bgra32); - var expected = new Bgra32(25, 0, 132, 255); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToArgb32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Argb32); - var expected = new Argb32(25, 0, 132, 255); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgr565); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgr565); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Bgr565_ToRgb24() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Rgb24); + // var expected = new Rgb24(25, 0, 132); + + // // act + // bgra.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_ToRgba32() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Rgba32); + // var expected = new Rgba32(25, 0, 132, 255); + + // // act + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_ToBgr24() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Bgr24); + // var expected = new Bgr24(25, 0, 132); + + // // act + // bgra.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_ToBgra32() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Bgra32); + // var expected = new Bgra32(25, 0, 132, 255); + + // // act + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_ToArgb32() + //{ + // // arrange + // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); + // var actual = default(Argb32); + // var expected = new Argb32(25, 0, 132, 255); + + // // act + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgr565); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgr565_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgr565); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 70f8c35dfc..9ff84a88c1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -103,80 +103,80 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); } - [Fact] - public void ToRgb24() - { - var c = new Bgra32(1, 2, 3, 4); - var dest = default(Rgb24); - - c.ToRgb24(ref dest); - - Assert.Equal(new Rgb24(1, 2, 3), dest); - } - - [Fact] - public void ToRgba32() - { - var c = new Bgra32(1, 2, 3, 4); - var rgba = default(Rgba32); - - c.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Bgra32(1, 2, 3, 4); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Bgra32(1, 2, 3, 4); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); - } - - [Fact] - public void Bgra32_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra32_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void ToRgb24() + //{ + // var c = new Bgra32(1, 2, 3, 4); + // var dest = default(Rgb24); + + // c.ToRgb24(ref dest); + + // Assert.Equal(new Rgb24(1, 2, 3), dest); + //} + + //[Fact] + //public void ToRgba32() + //{ + // var c = new Bgra32(1, 2, 3, 4); + // var rgba = default(Rgba32); + + // c.ToRgba32(ref rgba); + + // Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); + //} + + //[Fact] + //public void ToBgr24() + //{ + // var rgb = new Bgra32(1, 2, 3, 4); + // var bgr = default(Bgr24); + + // rgb.ToBgr24(ref bgr); + + // Assert.Equal(new Bgr24(1, 2, 3), bgr); + //} + + //[Fact] + //public void ToBgra32() + //{ + // var rgb = new Bgra32(1, 2, 3, 4); + // var bgra = default(Bgra32); + + // rgb.ToBgra32(ref bgra); + + // Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); + //} + + //[Fact] + //public void Bgra32_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgra32); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra32_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgra32); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index f643d152ef..2e6e339b6a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -71,159 +71,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Bgra4444_ToRgb24() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(34, 0, 136); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToRgba32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(34, 0, 136, 0); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToBgr24() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(34, 0, 136); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToBgra32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(34, 0, 136, 0); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToArgb32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(34, 0, 136, 0); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgba32_ToRgba32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Rgba32); - var expected = new Rgba32(34, 0, 136, 0); - - // act - bgra.PackFromRgba32(expected); - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromBgra32_ToBgra32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Bgra32); - var expected = new Bgra32(34, 0, 136, 0); - - // act - bgra.PackFromBgra32(expected); - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromArgb32_ToArgb32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Argb32); - var expected = new Argb32(34, 0, 136, 0); - - // act - bgra.PackFromArgb32(expected); - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra4444); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra4444); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Bgra4444_ToRgb24() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(34, 0, 136); + + // // act + // bgra.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_ToRgba32() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(34, 0, 136, 0); + + // // act + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_ToBgr24() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(34, 0, 136); + + // // act + // bgra.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_ToBgra32() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(34, 0, 136, 0); + + // // act + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_ToArgb32() + //{ + // // arrange + // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(34, 0, 136, 0); + + // // act + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var bgra = default(Bgra4444); + // var actual = default(Rgba32); + // var expected = new Rgba32(34, 0, 136, 0); + + // // act + // bgra.PackFromRgba32(expected); + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var bgra = default(Bgra4444); + // var actual = default(Bgra32); + // var expected = new Bgra32(34, 0, 136, 0); + + // // act + // bgra.PackFromBgra32(expected); + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var bgra = default(Bgra4444); + // var actual = default(Argb32); + // var expected = new Argb32(34, 0, 136, 0); + + // // act + // bgra.PackFromArgb32(expected); + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgra4444); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra4444_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgra4444); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index b6a0780312..3a0aec3209 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -70,159 +70,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Bgra5551_ToRgb24() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(24, 0, 131); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_Rgba32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(24, 0, 131, 0); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_ToBgr24() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(24, 0, 131); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_Bgra32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(24, 0, 131, 0); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_ToArgb32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(24, 0, 131, 0); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgba32_ToRgba32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Rgba32(24, 0, 131, 0); - var actual = default(Rgba32); - - // act - bgra.PackFromRgba32(expected); - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromBgra32_ToBgra32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Bgra32(24, 0, 131, 0); - var actual = default(Bgra32); - - // act - bgra.PackFromBgra32(expected); - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromArgb32_ToArgb32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Argb32(24, 0, 131, 0); - var actual = default(Argb32); - - // act - bgra.PackFromArgb32(expected); - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra5551); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra5551); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Bgra5551_ToRgb24() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(24, 0, 131); + + // // act + // bgra.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_Rgba32() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(24, 0, 131, 0); + + // // act + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_ToBgr24() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(24, 0, 131); + + // // act + // bgra.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_Bgra32() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(24, 0, 131, 0); + + // // act + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_ToArgb32() + //{ + // // arrange + // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(24, 0, 131, 0); + + // // act + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var bgra = default(Bgra5551); + // var expected = new Rgba32(24, 0, 131, 0); + // var actual = default(Rgba32); + + // // act + // bgra.PackFromRgba32(expected); + // bgra.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var bgra = default(Bgra5551); + // var expected = new Bgra32(24, 0, 131, 0); + // var actual = default(Bgra32); + + // // act + // bgra.PackFromBgra32(expected); + // bgra.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var bgra = default(Bgra5551); + // var expected = new Argb32(24, 0, 131, 0); + // var actual = default(Argb32); + + // // act + // bgra.PackFromArgb32(expected); + // bgra.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Bgra5551); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Bgra5551_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Bgra5551); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 28555a7dff..d1e8cceaa4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -68,159 +68,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Byte4_ToRgb24() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(128, 0, 0); - - // act - byte4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Rgba32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(128, 0, 0, 0); - - // act - byte4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_ToBgr24() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(128, 0, 0); - - // act - byte4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Bgra32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(128, 0, 0, 0); - - // act - byte4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Argb32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(128, 0, 0, 0); - - // act - byte4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgba32_ToRgba32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 0, 255); - - // act - byte4.PackFromRgba32(expected); - byte4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromBgra32_ToBgra32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 0, 255); - - // act - byte4.PackFromBgra32(expected); - byte4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromArgb32_ToArgb32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 0, 255); - - // act - byte4.PackFromArgb32(expected); - byte4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Byte4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Byte4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Byte4_ToRgb24() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(128, 0, 0); + + // // act + // byte4.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_Rgba32() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(128, 0, 0, 0); + + // // act + // byte4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_ToBgr24() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(128, 0, 0); + + // // act + // byte4.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_Bgra32() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(128, 0, 0, 0); + + // // act + // byte4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_Argb32() + //{ + // // arrange + // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(128, 0, 0, 0); + + // // act + // byte4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var byte4 = default(Byte4); + // var actual = default(Rgba32); + // var expected = new Rgba32(20, 38, 0, 255); + + // // act + // byte4.PackFromRgba32(expected); + // byte4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var byte4 = default(Byte4); + // var actual = default(Bgra32); + // var expected = new Bgra32(20, 38, 0, 255); + + // // act + // byte4.PackFromBgra32(expected); + // byte4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var byte4 = default(Byte4); + // var actual = default(Argb32); + // var expected = new Argb32(20, 38, 0, 255); + + // // act + // byte4.PackFromArgb32(expected); + // byte4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Byte4); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Byte4_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Byte4); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs deleted file mode 100644 index b0d5929f49..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Collections.Generic; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - public class ColorConstructorTests - { - public static IEnumerable Vector4Data - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector4), vector4Components }; - yield return new object[] { new Bgra4444(vector4), vector4Components }; - yield return new object[] { new Bgra5551(vector4), vector4Components }; - yield return new object[] { new Byte4(vector4), vector4Components }; - yield return new object[] { new HalfVector4(vector4), vector4Components }; - yield return new object[] { new NormalizedByte4(vector4), vector4Components }; - yield return new object[] { new NormalizedShort4(vector4), vector4Components }; - yield return new object[] { new Rgba1010102(vector4), vector4Components }; - yield return new object[] { new Rgba64(vector4), vector4Components }; - yield return new object[] { new Short4(vector4), vector4Components }; - } - } - } - - public static IEnumerable Vector3Data - { - get - { - Dictionary vector3Values = new Dictionary() - { - { Vector3.One, Vector4.One }, - { Vector3.Zero, new Vector4(0, 0, 0, 1) }, - { Vector3.UnitX, new Vector4(1, 0, 0, 1) }, - { Vector3.UnitY, new Vector4(0, 1, 0, 1) }, - { Vector3.UnitZ, new Vector4(0, 0, 1, 1) }, - }; - - foreach (Vector3 vector3 in vector3Values.Keys) - { - Vector4 vector4 = vector3Values[vector3]; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector3), vector4Components }; - yield return new object[] { new Bgr565(vector3), vector4Components }; - } - } - } - - public static IEnumerable Float4Data - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Bgra4444(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Bgra5551(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Byte4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new HalfVector4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new NormalizedByte4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new NormalizedShort4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Rgba1010102(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Rgba64(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Short4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - } - } - } - - public static IEnumerable Float3Data - { - get - { - Dictionary vector3Values = new Dictionary() - { - { Vector3.One, Vector4.One }, - { Vector3.Zero, new Vector4(0, 0, 0, 1) }, - { Vector3.UnitX, new Vector4(1, 0, 0, 1) }, - { Vector3.UnitY, new Vector4(0, 1, 0, 1) }, - { Vector3.UnitZ, new Vector4(0, 0, 1, 1) }, - }; - - foreach (Vector3 vector3 in vector3Values.Keys) - { - Vector4 vector4 = vector3Values[vector3]; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector3.X, vector3.Y, vector3.Z), vector4Components }; - yield return new object[] { new Bgr565(vector3.X, vector3.Y, vector3.Z), vector4Components }; - } - } - } - - [Theory] - [MemberData(nameof(Vector4Data))] - [MemberData(nameof(Vector3Data))] - [MemberData(nameof(Float4Data))] - [MemberData(nameof(Float3Data))] - public void ConstructorToVector4(IPixel packedVector, float[] expectedVector4Components) - { - // Arrange - int precision = 2; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - Vector4 expectedVector4 = new Vector4(expectedVector4Components[0], expectedVector4Components[1], expectedVector4Components[2], expectedVector4Components[3]); - - // Act - Vector4 vector4 = packedVector.ToVector4(); - - // Assert - Assert.Equal(expectedVector4.X, vector4.X, precision); - Assert.Equal(expectedVector4.Y, vector4.Y, precision); - Assert.Equal(expectedVector4.Z, vector4.Z, precision); - Assert.Equal(expectedVector4.W, vector4.W, precision); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs deleted file mode 100644 index d3815f2eb6..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - /// - /// Test implementations of IEquatable - /// - public class ColorEqualityTests - { - public static readonly TheoryData EqualityData = - new TheoryData() - { - { new Alpha8(.5F), new Alpha8(.5F), typeof(Alpha8) }, - { new Argb32(Vector4.One), new Argb32(Vector4.One), typeof(Argb32) }, - { new Bgr565(Vector3.One), new Bgr565(Vector3.One), typeof(Bgr565) }, - { new Bgra4444(Vector4.One), new Bgra4444(Vector4.One), typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), new Bgra5551(Vector4.One), typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), new Byte4(Vector4.One * 255), typeof(Byte4) }, - { new HalfSingle(-1F), new HalfSingle(-1F), typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), new HalfVector2(0.1f, -0.3f), typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), new HalfVector4(Vector4.One), typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), new NormalizedByte2(-Vector2.One), typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), new NormalizedByte4(Vector4.One), typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), new NormalizedShort2(Vector2.One), typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.One), typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), new Rg32(Vector2.One), typeof(Rg32) }, - { new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.One), typeof(Rgba1010102) }, - { new Rgba32(Vector4.One), new Rgba32(Vector4.One), typeof(Rgba32) }, - { new Rgba64(Vector4.One), new Rgba64(Vector4.One), typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.One * 0x7FFF), typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.One * 0x7FFF), typeof(Short4) }, - }; - - public static readonly TheoryData NotEqualityDataNulls = - new TheoryData() - { - // Valid object against null - { new Alpha8(.5F), null, typeof(Alpha8) }, - { new Argb32(Vector4.One), null, typeof(Argb32) }, - { new Bgr565(Vector3.One), null, typeof(Bgr565) }, - { new Bgra4444(Vector4.One), null, typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), null, typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), null, typeof(Byte4) }, - { new HalfSingle(-1F), null, typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), null, typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), null, typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), null, typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), null, typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), null, typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), null, typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), null, typeof(Rg32) }, - { new Rgba1010102(Vector4.One), null, typeof(Rgba1010102) }, - { new Rgba64(Vector4.One), null, typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), null, typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), null, typeof(Short4) }, - }; - - public static readonly TheoryData NotEqualityDataDifferentObjects = - new TheoryData() - { - // Valid objects of different types but not equal - { new Alpha8(.5F), new Argb32(Vector4.Zero), null }, - { new HalfSingle(-1F), new NormalizedShort2(Vector2.Zero), null }, - { new Rgba1010102(Vector4.One), new Bgra5551(Vector4.Zero), null }, - }; - - public static readonly TheoryData NotEqualityData = - new TheoryData() - { - // Valid objects of the same type but not equal - { new Alpha8(.5F), new Alpha8(.8F), typeof(Alpha8) }, - { new Argb32(Vector4.One), new Argb32(Vector4.Zero), typeof(Argb32) }, - { new Bgr565(Vector3.One), new Bgr565(Vector3.Zero), typeof(Bgr565) }, - { new Bgra4444(Vector4.One), new Bgra4444(Vector4.Zero), typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), new Bgra5551(Vector4.Zero), typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), new Byte4(Vector4.Zero), typeof(Byte4) }, - { new HalfSingle(-1F), new HalfSingle(1F), typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), new HalfVector2(0.1f, 0.3f), typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), new HalfVector4(Vector4.Zero), typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), new NormalizedByte2(-Vector2.Zero), typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), new NormalizedByte4(Vector4.Zero), typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), new NormalizedShort2(Vector2.Zero), typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.Zero), typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), new Rg32(Vector2.Zero), typeof(Rg32) }, - { new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.Zero), typeof(Rgba1010102) }, - { new Rgba32(Vector4.One), new Rgba32(Vector4.Zero), typeof(Rgba32) }, - { new Rgba64(Vector4.One), new Rgba64(Vector4.Zero), typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.Zero), typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.Zero), typeof(Short4) }, - }; - - [Theory] - [MemberData(nameof(EqualityData))] - public void Equality(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataNulls))] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - [MemberData(nameof(NotEqualityData))] - public void NotEquality(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void HashCodeEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - public void HashCodeNotEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void EqualityObject(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityData))] - public void NotEqualityObject(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void EqualityOperator(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject == secondObject; - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityData))] - public void NotEqualityOperator(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic notEqual = firstObject != secondObject; - - // Assert - Assert.True(notEqual); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs deleted file mode 100644 index c9a1c8fe7e..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Collections.Generic; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - public class ColorPackingTests - { - public static IEnumerable Vector4PackData - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { default(Argb32), vector4Components }; - yield return new object[] { default(Bgra4444), vector4Components }; - yield return new object[] { default(Bgra5551), vector4Components }; - yield return new object[] { default(Byte4), vector4Components }; - yield return new object[] { default(HalfVector4), vector4Components }; - yield return new object[] { default(NormalizedByte4), vector4Components }; - yield return new object[] { default(NormalizedShort4), vector4Components }; - yield return new object[] { default(Rgba1010102), vector4Components }; - yield return new object[] { default(Rgba64), vector4Components }; - yield return new object[] { default(Short4), vector4Components }; - } - } - } - - public static IEnumerable Vector3PackData - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.One, - new Vector4(0, 0, 0, 1), - new Vector4(1, 0, 0, 1), - new Vector4(0, 1, 0, 1), - new Vector4(0, 0, 1, 1), - }; - - foreach (Vector4 vector4 in vector4Values) - { - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { default(Argb32), vector4Components }; - yield return new object[] { new Bgr565(), vector4Components }; - } - } - } - - [Theory] - [MemberData(nameof(Vector4PackData))] - [MemberData(nameof(Vector3PackData))] - public void FromVector4ToVector4(IPixel packedVector, float[] vector4ComponentsToPack) - { - // Arrange - int precision = 2; - Vector4 vector4ToPack = new Vector4(vector4ComponentsToPack[0], vector4ComponentsToPack[1], vector4ComponentsToPack[2], vector4ComponentsToPack[3]); - packedVector.PackFromVector4(vector4ToPack); - - // Act - Vector4 vector4 = packedVector.ToVector4(); - - // Assert - Assert.Equal(vector4ToPack.X, vector4.X, precision); - Assert.Equal(vector4ToPack.Y, vector4.Y, precision); - Assert.Equal(vector4ToPack.Z, vector4.Z, precision); - Assert.Equal(vector4ToPack.W, vector4.W, precision); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index 2525ee3796..166fb230ac 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -19,193 +19,193 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(input, new Gray16(input).PackedValue); } - [Theory] - [InlineData(0)] - [InlineData(65535)] - [InlineData(32767)] - public void Gray16_ToVector4(ushort input) - { - // arrange - var gray = new Gray16(input); - - // act - var actual = gray.ToVector4(); - - // assert - Assert.Equal(input, actual.X); - Assert.Equal(input, actual.Y); - Assert.Equal(input, actual.Z); - Assert.Equal(1, actual.W); - } - - [Theory] - [InlineData(0)] - [InlineData(65535)] - [InlineData(32767)] - public void Gray16_ToScaledVector4(ushort input) - { - // arrange - var gray = new Gray16(input); - - // act - var actual = gray.ToScaledVector4(); - - // assert - float scaledInput = input / 65535f; - Assert.Equal(scaledInput, actual.X); - Assert.Equal(scaledInput, actual.Y); - Assert.Equal(scaledInput, actual.Z); - Assert.Equal(1, actual.W); - } - - [Fact] - public void Gray16_PackFromScaledVector4() - { - // arrange - Gray16 gray = default; - int expected = 32767; - Vector4 scaled = new Gray16((ushort)expected).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - ushort actual = gray.PackedValue; - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToRgb24() - { - // arrange - Rgb24 actual = default; - Gray16 gray = default; - var expected = new Rgb24(128, 128, 128); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToRgba32() - { - // arrange - Rgba32 actual = default; - Gray16 gray = default; - var expected = new Rgba32(128, 128, 128, 255); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToBgr24() - { - // arrange - Bgr24 actual = default; - Gray16 gray = default; - var expected = new Bgr24(128, 128, 128); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToBgra32() - { - // arrange - Bgra32 actual = default; - Gray16 gray = default; - var expected = new Bgra32(128,128,128); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToArgb32() - { - // arrange - Gray16 gray = default; - Argb32 actual = default; - var expected = new Argb32(128, 128, 128); - Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromScaledVector4_ToRgba64() - { - // arrange - Gray16 gray = default; - Rgba64 actual = default; - var expected = new Rgba64(65535, 65535, 65535, 65535); - Vector4 scaled = new Gray16(65535).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromRgb48_ToRgb48() - { - // arrange - var gray = default(Gray16); - var actual = default(Rgb48); - var expected = new Rgb48(0, 0, 0); - - // act - gray.PackFromRgb48(expected); - gray.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray16_PackFromRgba64_ToRgba64() - { - // arrange - var gray = default(Gray16); - var actual = default(Rgba64); - var expected = new Rgba64(0, 0, 0, 65535); - - // act - gray.PackFromRgba64(expected); - gray.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Theory] + //[InlineData(0)] + //[InlineData(65535)] + //[InlineData(32767)] + //public void Gray16_ToVector4(ushort input) + //{ + // // arrange + // var gray = new Gray16(input); + + // // act + // var actual = gray.ToVector4(); + + // // assert + // Assert.Equal(input, actual.X); + // Assert.Equal(input, actual.Y); + // Assert.Equal(input, actual.Z); + // Assert.Equal(1, actual.W); + //} + + //[Theory] + //[InlineData(0)] + //[InlineData(65535)] + //[InlineData(32767)] + //public void Gray16_ToScaledVector4(ushort input) + //{ + // // arrange + // var gray = new Gray16(input); + + // // act + // var actual = gray.ToScaledVector4(); + + // // assert + // float scaledInput = input / 65535f; + // Assert.Equal(scaledInput, actual.X); + // Assert.Equal(scaledInput, actual.Y); + // Assert.Equal(scaledInput, actual.Z); + // Assert.Equal(1, actual.W); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4() + //{ + // // arrange + // Gray16 gray = default; + // int expected = 32767; + // Vector4 scaled = new Gray16((ushort)expected).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // ushort actual = gray.PackedValue; + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToRgb24() + //{ + // // arrange + // Rgb24 actual = default; + // Gray16 gray = default; + // var expected = new Rgb24(128, 128, 128); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToRgba32() + //{ + // // arrange + // Rgba32 actual = default; + // Gray16 gray = default; + // var expected = new Rgba32(128, 128, 128, 255); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToBgr24() + //{ + // // arrange + // Bgr24 actual = default; + // Gray16 gray = default; + // var expected = new Bgr24(128, 128, 128); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToBgra32() + //{ + // // arrange + // Bgra32 actual = default; + // Gray16 gray = default; + // var expected = new Bgra32(128,128,128); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToArgb32() + //{ + // // arrange + // Gray16 gray = default; + // Argb32 actual = default; + // var expected = new Argb32(128, 128, 128); + // Vector4 scaled = new Gray16(32768).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromScaledVector4_ToRgba64() + //{ + // // arrange + // Gray16 gray = default; + // Rgba64 actual = default; + // var expected = new Rgba64(65535, 65535, 65535, 65535); + // Vector4 scaled = new Gray16(65535).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var gray = default(Gray16); + // var actual = default(Rgb48); + // var expected = new Rgb48(0, 0, 0); + + // // act + // gray.PackFromRgb48(expected); + // gray.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray16_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var gray = default(Gray16); + // var actual = default(Rgba64); + // var expected = new Rgba64(0, 0, 0, 65535); + + // // act + // gray.PackFromRgba64(expected); + // gray.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index 64ad0bff60..ae114a0e26 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -19,24 +19,24 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(input, new Gray8(input).PackedValue); } - [Theory] - [InlineData(0)] - [InlineData(255)] - [InlineData(30)] - public void Gray8_ToVector4(byte input) - { - // arrange - var gray = new Gray8(input); - - // act - var actual = gray.ToVector4(); - - // assert - Assert.Equal(input, actual.X); - Assert.Equal(input, actual.Y); - Assert.Equal(input, actual.Z); - Assert.Equal(1, actual.W); - } + //[Theory] + //[InlineData(0, 0)] + //[InlineData(255, 1)] + //[InlineData(30)] + //public void Gray8_ToVector4(byte input) + //{ + // // arrange + // var gray = new Gray8(input); + + // // act + // var actual = gray.ToVector4(); + + // // assert + // Assert.Equal(input, actual.X); + // Assert.Equal(input, actual.Y); + // Assert.Equal(input, actual.Z); + // Assert.Equal(1, actual.W); + //} [Theory] [InlineData(0)] @@ -74,138 +74,138 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void Gray8_PackFromScaledVector4_ToRgb24() - { - // arrange - Rgb24 actual = default; - Gray8 gray = default; - var expected = new Rgb24(128, 128, 128); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToRgba32() - { - // arrange - Rgba32 actual = default; - Gray8 gray = default; - var expected = new Rgba32(128, 128, 128, 255); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToBgr24() - { - // arrange - Bgr24 actual = default; - Gray8 gray = default; - var expected = new Bgr24(128, 128, 128); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToBgra32() - { - // arrange - Bgra32 actual = default; - Gray8 gray = default; - var expected = new Bgra32(128,128,128); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToArgb32() - { - // arrange - Gray8 gray = default; - Argb32 actual = default; - var expected = new Argb32(128, 128, 128); - Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromScaledVector4_ToRgba64() - { - // arrange - Gray8 gray = default; - Rgba64 actual = default; - var expected = new Rgba64(65535, 65535, 65535, 65535); - Vector4 scaled = new Gray8(255).ToScaledVector4(); - - // act - gray.PackFromScaledVector4(scaled); - gray.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromRgb48_ToRgb48() - { - // arrange - var gray = default(Gray8); - var actual = default(Rgb48); - var expected = new Rgb48(0, 0, 0); - - // act - gray.PackFromRgb48(expected); - gray.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Gray8_PackFromRgba64_ToRgba64() - { - // arrange - var gray = default(Gray8); - var actual = default(Rgba64); - var expected = new Rgba64(0, 0, 0, 65535); - - // act - gray.PackFromRgba64(expected); - gray.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Gray8_PackFromScaledVector4_ToRgb24() + //{ + // // arrange + // Rgb24 actual = default; + // Gray8 gray = default; + // var expected = new Rgb24(128, 128, 128); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToRgba32() + //{ + // // arrange + // Rgba32 actual = default; + // Gray8 gray = default; + // var expected = new Rgba32(128, 128, 128, 255); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToBgr24() + //{ + // // arrange + // Bgr24 actual = default; + // Gray8 gray = default; + // var expected = new Bgr24(128, 128, 128); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToBgra32() + //{ + // // arrange + // Bgra32 actual = default; + // Gray8 gray = default; + // var expected = new Bgra32(128,128,128); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToArgb32() + //{ + // // arrange + // Gray8 gray = default; + // Argb32 actual = default; + // var expected = new Argb32(128, 128, 128); + // Vector4 scaled = new Gray8(128).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromScaledVector4_ToRgba64() + //{ + // // arrange + // Gray8 gray = default; + // Rgba64 actual = default; + // var expected = new Rgba64(65535, 65535, 65535, 65535); + // Vector4 scaled = new Gray8(255).ToScaledVector4(); + + // // act + // gray.PackFromScaledVector4(scaled); + // gray.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var gray = default(Gray8); + // var actual = default(Rgb48); + // var expected = new Rgb48(0, 0, 0); + + // // act + // gray.PackFromRgb48(expected); + // gray.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Gray8_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var gray = default(Gray8); + // var actual = default(Rgba64); + // var expected = new Rgba64(0, 0, 0, 65535); + + // // act + // gray.PackFromRgba64(expected); + // gray.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 3376645f34..1c3905854e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -67,111 +67,111 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void HalfSingle_ToRgb24() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Rgb24); - var expected = new Rgb24(128, 0, 0); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Rgba32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Rgba32); - var expected = new Rgba32(128, 0, 0, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_ToBgr24() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Bgr24); - var expected = new Bgr24(128, 0, 0); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Bgra32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Bgra32); - var expected = new Bgra32(128, 0, 0, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Argb32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Argb32); - var expected = new Argb32(128, 0, 0, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfSingle); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfSingle); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void HalfSingle_ToRgb24() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Rgb24); + // var expected = new Rgb24(128, 0, 0); + + // // act + // halfVector.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_Rgba32() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Rgba32); + // var expected = new Rgba32(128, 0, 0, 255); + + // // act + // halfVector.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_ToBgr24() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Bgr24); + // var expected = new Bgr24(128, 0, 0); + + // // act + // halfVector.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_Bgra32() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Bgra32); + // var expected = new Bgra32(128, 0, 0, 255); + + // // act + // halfVector.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_Argb32() + //{ + // // arrange + // var halfVector = new HalfSingle(.5F); + // var actual = default(Argb32); + // var expected = new Argb32(128, 0, 0, 255); + + // // act + // halfVector.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(HalfSingle); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfSingle_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(HalfSingle); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index c2a524f0dc..1ceb224e5e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -72,111 +72,111 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void HalfVector2_ToRgb24() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Rgb24); - var expected = new Rgb24(128, 64, 0); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Rgba32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Rgba32); - var expected = new Rgba32(128, 64, 0, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_ToBgr24() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Bgr24); - var expected = new Bgr24(128, 64, 0); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Bgra32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Bgra32); - var expected = new Bgra32(128, 64, 0, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Argb32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Argb32); - var expected = new Argb32(128, 64, 0, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfVector2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfVector2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void HalfVector2_ToRgb24() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Rgb24); + // var expected = new Rgb24(128, 64, 0); + + // // act + // halfVector.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_Rgba32() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Rgba32); + // var expected = new Rgba32(128, 64, 0, 255); + + // // act + // halfVector.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_ToBgr24() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Bgr24); + // var expected = new Bgr24(128, 64, 0); + + // // act + // halfVector.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_Bgra32() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Bgra32); + // var expected = new Bgra32(128, 64, 0, 255); + + // // act + // halfVector.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_Argb32() + //{ + // // arrange + // var halfVector = new HalfVector2(.5F, .25F); + // var actual = default(Argb32); + // var expected = new Argb32(128, 64, 0, 255); + + // // act + // halfVector.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(HalfVector2); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector2_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(HalfVector2); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 8b28dd8277..3ba5718503 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -66,159 +66,159 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void HalfVector4_ToRgb24() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Rgb24); - var expected = new Rgb24(64, 128, 191); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Rgba32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Rgba32); - var expected = new Rgba32(64, 128, 191, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_ToBgr24() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Bgr24); - var expected = new Bgr24(64, 128, 191); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Bgra32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Bgra32); - var expected = new Bgra32(64, 128, 191, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Argb32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Argb32); - var expected = new Argb32(64, 128, 191, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgba32_ToRgba32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Rgba32); - var expected = new Rgba32(64, 128, 191, 255); - - // act - halVector.PackFromRgba32(expected); - halVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromBgra32_ToBgra32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Bgra32); - var expected = new Bgra32(64, 128, 191, 255); - - // act - halVector.PackFromBgra32(expected); - halVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromArgb32_ToArgb32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Argb32); - var expected = new Argb32(64, 128, 191, 255); - - // act - halVector.PackFromArgb32(expected); - halVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfVector4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfVector4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void HalfVector4_ToRgb24() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Rgb24); + // var expected = new Rgb24(64, 128, 191); + + // // act + // halfVector.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_Rgba32() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Rgba32); + // var expected = new Rgba32(64, 128, 191, 255); + + // // act + // halfVector.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_ToBgr24() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Bgr24); + // var expected = new Bgr24(64, 128, 191); + + // // act + // halfVector.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_Bgra32() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Bgra32); + // var expected = new Bgra32(64, 128, 191, 255); + + // // act + // halfVector.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_Argb32() + //{ + // // arrange + // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); + // var actual = default(Argb32); + // var expected = new Argb32(64, 128, 191, 255); + + // // act + // halfVector.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var halVector = default(HalfVector4); + // var actual = default(Rgba32); + // var expected = new Rgba32(64, 128, 191, 255); + + // // act + // halVector.PackFromRgba32(expected); + // halVector.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var halVector = default(HalfVector4); + // var actual = default(Bgra32); + // var expected = new Bgra32(64, 128, 191, 255); + + // // act + // halVector.PackFromBgra32(expected); + // halVector.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var halVector = default(HalfVector4); + // var actual = default(Argb32); + // var expected = new Argb32(64, 128, 191, 255); + + // // act + // halVector.PackFromArgb32(expected); + // halVector.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(HalfVector4); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void HalfVector4_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(HalfVector4); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 83f22e2aa0..3ab36853b9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -67,127 +67,127 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void NormalizedByte2_PackFromRgba32() - { - // arrange - var byte2 = new NormalizedByte2(); - var rgba = new Rgba32(141, 90, 0, 0); - int expected = 0xda0d; - - // act - byte2.PackFromRgba32(rgba); - ushort actual = byte2.PackedValue; - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToRgb24() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 0); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToRgba32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 0, 255); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToBgr24() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 0); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToBgra32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Bgra32); - var expected = new Bgra32(141, 90, 0, 255); - - // act - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToArgb32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 0, 255); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedByte2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedByte2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void NormalizedByte2_PackFromRgba32() + //{ + // // arrange + // var byte2 = new NormalizedByte2(); + // var rgba = new Rgba32(141, 90, 0, 0); + // int expected = 0xda0d; + + // // act + // byte2.PackFromRgba32(rgba); + // ushort actual = byte2.PackedValue; + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToRgb24() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Rgb24); + // var expected = new Rgb24(141, 90, 0); + + // // act + // short4.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToRgba32() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Rgba32); + // var expected = new Rgba32(141, 90, 0, 255); + + // // act + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToBgr24() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Bgr24); + // var expected = new Bgr24(141, 90, 0); + + // // act + // short4.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToBgra32() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Bgra32); + // var expected = new Bgra32(141, 90, 0, 255); + + // // act + // short4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_ToArgb32() + //{ + // // arrange + // var short4 = new NormalizedByte2(0.1f, -0.3f); + // var actual = default(Argb32); + // var expected = new Argb32(141, 90, 0, 255); + + // // act + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(NormalizedByte2); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte2_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(NormalizedByte2); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 16516496f8..acac04853f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -61,144 +61,144 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void NormalizedByte4_ToRgb24() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 192); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToRgba32() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 192, 39); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToBgr24() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 192); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToArgb32() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 192, 39); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgba32_ToRgba32() - { - // arrange - var short4 = default(NormalizedByte4); - var actual = default(Rgba32); - var expected = new Rgba32(9, 115, 202, 127); - - // act - short4.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromBgra32_ToRgba32() - { - // arrange - var actual = default(Bgra32); - var short4 = default(NormalizedByte4); - var expected = new Bgra32(9, 115, 202, 127); - - // act - short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromArgb32_ToRgba32() - { - // arrange - var short4 = default(NormalizedByte4); - var actual = default(Argb32); - var expected = new Argb32(9, 115, 202, 127); - - // act - short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedByte4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedByte4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void NormalizedByte4_ToRgb24() + //{ + // // arrange + // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(141, 90, 192); + + // // act + // short4.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_ToRgba32() + //{ + // // arrange + // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(141, 90, 192, 39); + + // // act + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_ToBgr24() + //{ + // // arrange + // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(141, 90, 192); + + // // act + // short4.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_ToArgb32() + //{ + // // arrange + // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(141, 90, 192, 39); + + // // act + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedByte4); + // var actual = default(Rgba32); + // var expected = new Rgba32(9, 115, 202, 127); + + // // act + // short4.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromBgra32_ToRgba32() + //{ + // // arrange + // var actual = default(Bgra32); + // var short4 = default(NormalizedByte4); + // var expected = new Bgra32(9, 115, 202, 127); + + // // act + // short4.PackFromBgra32(expected); + // short4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromArgb32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedByte4); + // var actual = default(Argb32); + // var expected = new Argb32(9, 115, 202, 127); + + // // act + // short4.PackFromArgb32(expected); + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(NormalizedByte4); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedByte4_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(NormalizedByte4); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 2fb7f05aca..e02d513c2a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -70,128 +70,128 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void NormalizedShort2_PackFromRgba32_ToRgb24() - { - // arrange - var actual = default(Rgb24); - var short2 = new NormalizedShort2(); - var rgba = new Rgba32(141, 90, 0, 0); - var expected = new Rgb24(141, 90, 0); - - // act - short2.PackFromRgba32(rgba); - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToRgb24() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 0); - - // act - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToRgba32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 0, 255); - - // act - short2.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToBgr24() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 0); - - // act - short2.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToBgra32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Bgra32); - var expected = new Bgra32(141, 90, 0, 255); - - // act - short2.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToArgb32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 0, 255); - - // act - short2.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedShort2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedShort2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void NormalizedShort2_PackFromRgba32_ToRgb24() + //{ + // // arrange + // var actual = default(Rgb24); + // var short2 = new NormalizedShort2(); + // var rgba = new Rgba32(141, 90, 0, 0); + // var expected = new Rgb24(141, 90, 0); + + // // act + // short2.PackFromRgba32(rgba); + // short2.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToRgb24() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Rgb24); + // var expected = new Rgb24(141, 90, 0); + + // // act + // short2.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToRgba32() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Rgba32); + // var expected = new Rgba32(141, 90, 0, 255); + + // // act + // short2.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToBgr24() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Bgr24); + // var expected = new Bgr24(141, 90, 0); + + // // act + // short2.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToBgra32() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Bgra32); + // var expected = new Bgra32(141, 90, 0, 255); + + // // act + // short2.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_ToArgb32() + //{ + // // arrange + // var short2 = new NormalizedShort2(0.1f, -0.3f); + // var actual = default(Argb32); + // var expected = new Argb32(141, 90, 0, 255); + + // // act + // short2.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(NormalizedShort2); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort2_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(NormalizedShort2); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 7dcdd9c88b..25ffbb348a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -62,144 +62,144 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void NormalizedShort4_ToRgb24() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 192); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToRgba32() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 192, 39); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToBgr24() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 192); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToArgb32() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 192, 39); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgba32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var expected = new Rgba32(9, 115, 202, 127); - var actual = default(Rgba32); - - // act - short4.PackFromRgba32(expected); - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromBgra32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var actual = default(Bgra32); - var expected = new Bgra32(9, 115, 202, 127); - - // act - short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromArgb32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var actual = default(Argb32); - var expected = new Argb32(9, 115, 202, 127); - - // act - short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedShort4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedShort4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void NormalizedShort4_ToRgb24() + //{ + // // arrange + // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(141, 90, 192); + + // // act + // short4.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_ToRgba32() + //{ + // // arrange + // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(141, 90, 192, 39); + + // // act + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_ToBgr24() + //{ + // // arrange + // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(141, 90, 192); + + // // act + // short4.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_ToArgb32() + //{ + // // arrange + // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Argb32); + // var expected = new Argb32(141, 90, 192, 39); + + // // act + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedShort4); + // var expected = new Rgba32(9, 115, 202, 127); + // var actual = default(Rgba32); + + // // act + // short4.PackFromRgba32(expected); + // short4.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromBgra32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedShort4); + // var actual = default(Bgra32); + // var expected = new Bgra32(9, 115, 202, 127); + + // // act + // short4.PackFromBgra32(expected); + // short4.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromArgb32_ToRgba32() + //{ + // // arrange + // var short4 = default(NormalizedShort4); + // var actual = default(Argb32); + // var expected = new Argb32(9, 115, 202, 127); + + // // act + // short4.PackFromArgb32(expected); + // short4.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(NormalizedShort4); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void NormalizedShort4_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(NormalizedShort4); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 9e41fd94f3..92b04f587e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -1,95 +1,89 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; -using Xunit.Abstractions; - -namespace SixLabors.ImageSharp.Tests.PixelFormats -{ - public partial class PixelOperationsTests - { - public class Rgba32 : PixelOperationsTests - { - public Rgba32(ITestOutputHelper output) - : base(output) - { - } - - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - [Fact] - public void IsSpecialImplementation() - { - Assert.IsType(PixelOperations.Instance); - } - - [Fact] - public void ToVector4SimdAligned() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) - ); - } - - - // [Fact] // Profiling benchmark - enable manually! -#pragma warning disable xUnit1013 // Public method should be marked as test - public void Benchmark_ToVector4() -#pragma warning restore xUnit1013 // Public method should be marked as test - { - int times = 200000; - int count = 1024; - - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) - using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) - { - this.Measure( - times, - () => - { - PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); - }); - } - } - } - - public class Argb32 : PixelOperationsTests - { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public Argb32(ITestOutputHelper output) - : base(output) - { - } - - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - } - - [Theory] - [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider dummy) - where TPixel : struct, IPixel - { - Assert.NotNull(PixelOperations.Instance); +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public partial class PixelOperationsTests + { + public class Rgba32 : PixelOperationsTests + { + public Rgba32(ITestOutputHelper output) + : base(output) + { + } + + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Fact] + public void ToVector4SimdAligned() + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) + ); + } + + + // [Fact] // Profiling benchmark - enable manually! +#pragma warning disable xUnit1013 // Public method should be marked as test + public void Benchmark_ToVector4() +#pragma warning restore xUnit1013 // Public method should be marked as test + { + int times = 200000; + int count = 1024; + + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) + { + this.Measure( + times, + () => + { + PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); + }); + } + } } + public class Argb32 : PixelOperationsTests + { + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public Argb32(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + } + + [Theory] + [WithBlankImages(1, 1, PixelTypes.All)] + public void GetGlobalInstance(TestImageProvider dummy) + where TPixel : struct, IPixel => Assert.NotNull(PixelOperations.Instance); + [Fact] public void IsOpaqueColor() { @@ -98,595 +92,593 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Transparent)); Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal,PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - } - } - - public abstract class PixelOperationsTests : MeasureFixture - where TPixel : struct, IPixel - { - protected PixelOperationsTests(ITestOutputHelper output) - : base(output) - { - } - - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - private static PixelOperations Operations => PixelOperations.Instance; - - internal static TPixel[] CreateExpectedPixelData(Vector4[] source) - { - var expected = new TPixel[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i].PackFromVector4(source[i]); - } - return expected; - } - - internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source) - { - var expected = new TPixel[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i].PackFromScaledVector4(source[i]); - } - return expected; - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromVector4(int count) - { - Vector4[] source = CreateVector4TestData(count); - TPixel[] expected = CreateExpectedPixelData(source); - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromScaledVector4(int count) - { - Vector4[] source = CreateVector4TestData(count); - TPixel[] expected = CreateScaledExpectedPixelData(source); - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) - ); - } - - internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToVector4(); - } - return expected; - } - - internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToScaledVector4(); - } - return expected; - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToVector4(int count) - { - TPixel[] source = CreatePixelTestData(count); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => Operations.ToVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToScaledVector4(int count) - { - TPixel[] source = CreateScaledPixelTestData(count); - Vector4[] expected = CreateExpectedScaledVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) - { - byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - - expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgb24Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - source[i].ToRgb24(ref rgb); - expected[i3] = rgb.R; - expected[i3 + 1] = rgb.G; - expected[i3 + 2] = rgb.B; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgba32Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToRgba32(ref rgba); - expected[i4] = rgba.R; - expected[i4 + 1] = rgba.G; - expected[i4 + 2] = rgba.B; - expected[i4 + 3] = rgba.A; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) - { - byte[] source = CreateByteTestData(count * 6); - Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; - - var rgba64 = new Rgba64(0, 0, 0, 65535); - for (int i = 0; i < count; i++) - { - int i6 = i * 6; - rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; - expected[i].PackFromRgba64(rgba64); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgb48Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; - - for (int i = 0; i < count; i++) - { - int i6 = i * 6; - source[i].ToRgb48(ref rgb); - Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); - expected[i6] = rgb48Bytes[0]; - expected[i6 + 1] = rgb48Bytes[1]; - expected[i6 + 2] = rgb48Bytes[2]; - expected[i6 + 3] = rgb48Bytes[3]; - expected[i6 + 4] = rgb48Bytes[4]; - expected[i6 + 5] = rgb48Bytes[5]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) - { - byte[] source = CreateByteTestData(count * 8); - Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgba64Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; - - for (int i = 0; i < count; i++) - { - int i8 = i * 8; - source[i].ToRgba64(ref rgba); - Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); - expected[i8] = rgba64Bytes[0]; - expected[i8 + 1] = rgba64Bytes[1]; - expected[i8 + 2] = rgba64Bytes[2]; - expected[i8 + 3] = rgba64Bytes[3]; - expected[i8 + 4] = rgba64Bytes[4]; - expected[i8 + 5] = rgba64Bytes[5]; - expected[i8 + 6] = rgba64Bytes[6]; - expected[i8 + 7] = rgba64Bytes[7]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) - { - byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - - expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToBgr24Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - source[i].ToBgr24(ref bgr); - expected[i3] = bgr.B; - expected[i3 + 1] = bgr.G; - expected[i3 + 2] = bgr.R; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToZyxwBytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToBgra32(ref bgra); - expected[i4] = bgra.B; - expected[i4 + 1] = bgra.G; - expected[i4 + 2] = bgra.R; - expected[i4 + 3] = bgra.A; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToArgb32Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var argb = default(Argb32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToArgb32(ref argb); - expected[i4] = argb.A; - expected[i4 + 1] = argb.R; - expected[i4 + 2] = argb.G; - expected[i4 + 3] = argb.B; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) - ); - } - - private class TestBuffers : IDisposable - where TSource : struct - where TDest : struct - { - public TSource[] SourceBuffer { get; } - public IMemoryOwner ActualDestBuffer { get; } - public TDest[] ExpectedDestBuffer { get; } - - public TestBuffers(TSource[] source, TDest[] expectedDest) - { - this.SourceBuffer = source; - this.ExpectedDestBuffer = expectedDest; - this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); - } - - public void Dispose() - { - this.ActualDestBuffer.Dispose(); - } - - private const float Tolerance = 0.0001f; - - public void Verify() - { - int count = this.ExpectedDestBuffer.Length; - - if (typeof(TDest) == typeof(Vector4)) - { - - Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); - Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - - for (int i = 0; i < count; i++) - { - // ReSharper disable PossibleNullReferenceException - Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); - // ReSharper restore PossibleNullReferenceException - } - } - else - { - Span expected = this.ExpectedDestBuffer.AsSpan(); - Span actual = this.ActualDestBuffer.GetSpan(); - for (int i = 0; i < count; i++) - { - Assert.Equal(expected[i], actual[i]); - } - } - } - } - - internal static void TestOperation( - TSource[] source, - TDest[] expected, - Action> action) - where TSource : struct - where TDest : struct - { - using (var buffers = new TestBuffers(source, expected)) - { - action(buffers.SourceBuffer, buffers.ActualDestBuffer); - buffers.Verify(); - } - } - - internal static Vector4[] CreateVector4TestData(int length) - { - var result = new Vector4[length]; - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - result[i] = GetVector(rnd); - } - return result; - } - - internal static TPixel[] CreatePixelTestData(int length) - { - var result = new TPixel[length]; - - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - Vector4 v = GetVector(rnd); - result[i].PackFromVector4(v); - } - - return result; - } - - internal static TPixel[] CreateScaledPixelTestData(int length) - { - var result = new TPixel[length]; - - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - Vector4 v = GetVector(rnd); - result[i].PackFromScaledVector4(v); - } - - return result; - } - - internal static byte[] CreateByteTestData(int length) - { - byte[] result = new byte[length]; - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - result[i] = (byte)rnd.Next(255); - } - return result; - } - - internal static Vector4 GetVector(Random rnd) - { - return new Vector4( - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble() - ); - } - - [StructLayout(LayoutKind.Sequential)] - private unsafe struct Rgba64Bytes - { - public fixed byte Data[8]; - - public byte this[int idx] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ref byte self = ref Unsafe.As(ref this); - return Unsafe.Add(ref self, idx); - } - } - } - } + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); + } + } + + public abstract class PixelOperationsTests : MeasureFixture + where TPixel : struct, IPixel + { + protected PixelOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + private static PixelOperations Operations => PixelOperations.Instance; + + internal static TPixel[] CreateExpectedPixelData(Vector4[] source) + { + var expected = new TPixel[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i].PackFromVector4(source[i]); + } + return expected; + } + + internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source) + { + var expected = new TPixel[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i].PackFromScaledVector4(source[i]); + } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromVector4(int count) + { + Vector4[] source = CreateVector4TestData(count); + TPixel[] expected = CreateExpectedPixelData(source); + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromScaledVector4(int count) + { + Vector4[] source = CreateVector4TestData(count); + TPixel[] expected = CreateScaledExpectedPixelData(source); + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) + ); + } + + internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToVector4(); + } + return expected; + } + + internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToScaledVector4(); + } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToVector4(int count) + { + TPixel[] source = CreatePixelTestData(count); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => Operations.ToVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToScaledVector4(int count) + { + TPixel[] source = CreateScaledPixelTestData(count); + Vector4[] expected = CreateExpectedScaledVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgb24Bytes(int count) + { + byte[] source = CreateByteTestData(count * 3); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgb24Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + var rgb = default(Rgb24); + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = rgb.R; + expected[i3 + 1] = rgb.G; + expected[i3 + 2] = rgb.B; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgba32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgba32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var rgba = default(Rgba32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = rgba.R; + expected[i4 + 1] = rgba.G; + expected[i4 + 2] = rgba.B; + expected[i4 + 3] = rgba.A; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgb48Bytes(int count) + { + byte[] source = CreateByteTestData(count * 6); + Span sourceSpan = source.AsSpan(); + var expected = new TPixel[count]; + + var rgba64 = new Rgba64(0, 0, 0, 65535); + for (int i = 0; i < count; i++) + { + int i6 = i * 6; + rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; + expected[i].PackFromRgba64(rgba64); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgb48Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 6]; + Rgb48 rgb = default; + + for (int i = 0; i < count; i++) + { + int i6 = i * 6; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); + expected[i6] = rgb48Bytes[0]; + expected[i6 + 1] = rgb48Bytes[1]; + expected[i6 + 2] = rgb48Bytes[2]; + expected[i6 + 3] = rgb48Bytes[3]; + expected[i6 + 4] = rgb48Bytes[4]; + expected[i6 + 5] = rgb48Bytes[5]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgba64Bytes(int count) + { + byte[] source = CreateByteTestData(count * 8); + Span sourceSpan = source.AsSpan(); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i8 = i * 8; + expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgba64Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 8]; + Rgba64 rgba = default; + + for (int i = 0; i < count; i++) + { + int i8 = i * 8; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); + expected[i8] = rgba64Bytes[0]; + expected[i8 + 1] = rgba64Bytes[1]; + expected[i8 + 2] = rgba64Bytes[2]; + expected[i8 + 3] = rgba64Bytes[3]; + expected[i8 + 4] = rgba64Bytes[4]; + expected[i8 + 5] = rgba64Bytes[5]; + expected[i8 + 6] = rgba64Bytes[6]; + expected[i8 + 7] = rgba64Bytes[7]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromBgr24Bytes(int count) + { + byte[] source = CreateByteTestData(count * 3); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToBgr24Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + var bgr = default(Bgr24); + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + bgr.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = bgr.B; + expected[i3 + 1] = bgr.G; + expected[i3 + 2] = bgr.R; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromBgra32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToBgra32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var bgra = default(Bgra32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + bgra.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = bgra.B; + expected[i4 + 1] = bgra.G; + expected[i4 + 2] = bgra.R; + expected[i4 + 3] = bgra.A; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromArgb32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToArgb32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var argb = default(Argb32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + argb.PackFromScaledVector4(source[i].ToScaledVector4()); + + expected[i4] = argb.A; + expected[i4 + 1] = argb.R; + expected[i4 + 2] = argb.G; + expected[i4 + 3] = argb.B; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + ); + } + + private class TestBuffers : IDisposable + where TSource : struct + where TDest : struct + { + public TSource[] SourceBuffer { get; } + public IMemoryOwner ActualDestBuffer { get; } + public TDest[] ExpectedDestBuffer { get; } + + public TestBuffers(TSource[] source, TDest[] expectedDest) + { + this.SourceBuffer = source; + this.ExpectedDestBuffer = expectedDest; + this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); + } + + public void Dispose() => this.ActualDestBuffer.Dispose(); + + private const float Tolerance = 0.0001f; + + public void Verify() + { + int count = this.ExpectedDestBuffer.Length; + + if (typeof(TDest) == typeof(Vector4)) + { + + Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); + Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); + + for (int i = 0; i < count; i++) + { + // ReSharper disable PossibleNullReferenceException + Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); + // ReSharper restore PossibleNullReferenceException + } + } + else + { + Span expected = this.ExpectedDestBuffer.AsSpan(); + Span actual = this.ActualDestBuffer.GetSpan(); + for (int i = 0; i < count; i++) + { + Assert.Equal(expected[i], actual[i]); + } + } + } + } + + internal static void TestOperation( + TSource[] source, + TDest[] expected, + Action> action) + where TSource : struct + where TDest : struct + { + using (var buffers = new TestBuffers(source, expected)) + { + action(buffers.SourceBuffer, buffers.ActualDestBuffer); + buffers.Verify(); + } + } + + internal static Vector4[] CreateVector4TestData(int length) + { + var result = new Vector4[length]; + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + result[i] = GetVector(rnd); + } + return result; + } + + internal static TPixel[] CreatePixelTestData(int length) + { + var result = new TPixel[length]; + + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromVector4(v); + } + + return result; + } + + internal static TPixel[] CreateScaledPixelTestData(int length) + { + var result = new TPixel[length]; + + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromScaledVector4(v); + } + + return result; + } + + internal static byte[] CreateByteTestData(int length) + { + byte[] result = new byte[length]; + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + result[i] = (byte)rnd.Next(255); + } + return result; + } + + internal static Vector4 GetVector(Random rnd) + { + return new Vector4( + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble() + ); + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct Rgba64Bytes + { + public fixed byte Data[8]; + + public byte this[int idx] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ref byte self = ref Unsafe.As(ref this); + return Unsafe.Add(ref self, idx); + } + } + } + } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 3a80c3436d..69ecc553e7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -69,96 +69,96 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2()); } - [Fact] - public void Rg32_ToRgb24() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 0); - - // act - rg32.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToRgba32() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 0, 255); - - // act - rg32.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToBgr24() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 0); - - // act - rg32.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToArgb32() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(25, 0, 0, 255); - - // act - rg32.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rg32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rg32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Rg32_ToRgb24() + //{ + // // arrange + // var rg32 = new Rg32(0.1f, -0.3f); + // var actual = default(Rgb24); + // var expected = new Rgb24(25, 0, 0); + + // // act + // rg32.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_ToRgba32() + //{ + // // arrange + // var rg32 = new Rg32(0.1f, -0.3f); + // var actual = default(Rgba32); + // var expected = new Rgba32(25, 0, 0, 255); + + // // act + // rg32.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_ToBgr24() + //{ + // // arrange + // var rg32 = new Rg32(0.1f, -0.3f); + // var actual = default(Bgr24); + // var expected = new Bgr24(25, 0, 0); + + // // act + // rg32.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_ToArgb32() + //{ + // // arrange + // var rg32 = new Rg32(0.1f, -0.3f); + // var actual = default(Argb32); + // var expected = new Argb32(25, 0, 0, 255); + + // // act + // rg32.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Rg32); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 65535, 0); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rg32_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Rg32); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 65535, 0, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index d056bf30d2..fcbef1374f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -1,175 +1,175 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.PixelFormats -{ - public class Rgb24Tests - { - public static readonly TheoryData ColorData = - new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; - - [Theory] - [MemberData(nameof(ColorData))] - public void Constructor(byte r, byte g, byte b) - { - var p = new Rgb24(r, g, b); - - Assert.Equal(r, p.R); - Assert.Equal(g, p.G); - Assert.Equal(b, p.B); - } - - [Fact] - public unsafe void ByteLayoutIsSequentialRgb() - { - var color = new Rgb24(1, 2, 3); - byte* ptr = (byte*)&color; - - Assert.Equal(1, ptr[0]); - Assert.Equal(2, ptr[1]); - Assert.Equal(3, ptr[2]); - } - - [Theory] - [MemberData(nameof(ColorData))] - public void Equals_WhenTrue(byte r, byte g, byte b) - { - var x = new Rgb24(r, g, b); - var y = new Rgb24(r, g, b); - - Assert.True(x.Equals(y)); - Assert.True(x.Equals((object)y)); - Assert.Equal(x.GetHashCode(), y.GetHashCode()); - } - - [Theory] - [InlineData(1, 2, 3, 1, 2, 4)] - [InlineData(0, 255, 0, 0, 244, 0)] - [InlineData(1, 255, 0, 0, 255, 0)] - public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) - { - var a = new Rgb24(r1, g1, b1); - var b = new Rgb24(r2, g2, b2); - - Assert.False(a.Equals(b)); - Assert.False(a.Equals((object)b)); - } - - [Fact] - public void PackFromRgba32() - { - var rgb = default(Rgb24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); - - Assert.Equal(1, rgb.R); - Assert.Equal(2, rgb.G); - Assert.Equal(3, rgb.B); - } - - private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( - r / 255f, - g / 255f, - b / 255f, - a / 255f); - - [Fact] - public void PackFromVector4() - { - var rgb = default(Rgb24); - rgb.PackFromVector4(Vec(1, 2, 3, 4)); - - Assert.Equal(1, rgb.R); - Assert.Equal(2, rgb.G); - Assert.Equal(3, rgb.B); - } - - [Fact] - public void ToVector4() - { - var rgb = new Rgb24(1, 2, 3); - - Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); - } - - [Fact] - public void ToRgb24() - { - var rgb = new Rgb24(1, 2, 3); - var dest = default(Rgb24); - - rgb.ToRgb24(ref dest); - - Assert.Equal(rgb, dest); - } - - [Fact] - public void ToRgba32() - { - var rgb = new Rgb24(1, 2, 3); - var rgba = default(Rgba32); - - rgb.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Rgb24(1, 2, 3); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Rgb24(1, 2, 3); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - } - - [Fact] - public void Rgb24_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgb24); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb24_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgb24); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - } -} \ No newline at end of file +//// Copyright (c) Six Labors and contributors. +//// Licensed under the Apache License, Version 2.0. + +//using System; +//using System.Numerics; +//using SixLabors.ImageSharp.PixelFormats; +//using Xunit; + +//namespace SixLabors.ImageSharp.Tests.PixelFormats +//{ +// public class Rgb24Tests +// { +// public static readonly TheoryData ColorData = +// new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; + +// [Theory] +// [MemberData(nameof(ColorData))] +// public void Constructor(byte r, byte g, byte b) +// { +// var p = new Rgb24(r, g, b); + +// Assert.Equal(r, p.R); +// Assert.Equal(g, p.G); +// Assert.Equal(b, p.B); +// } + +// [Fact] +// public unsafe void ByteLayoutIsSequentialRgb() +// { +// var color = new Rgb24(1, 2, 3); +// byte* ptr = (byte*)&color; + +// Assert.Equal(1, ptr[0]); +// Assert.Equal(2, ptr[1]); +// Assert.Equal(3, ptr[2]); +// } + +// [Theory] +// [MemberData(nameof(ColorData))] +// public void Equals_WhenTrue(byte r, byte g, byte b) +// { +// var x = new Rgb24(r, g, b); +// var y = new Rgb24(r, g, b); + +// Assert.True(x.Equals(y)); +// Assert.True(x.Equals((object)y)); +// Assert.Equal(x.GetHashCode(), y.GetHashCode()); +// } + +// [Theory] +// [InlineData(1, 2, 3, 1, 2, 4)] +// [InlineData(0, 255, 0, 0, 244, 0)] +// [InlineData(1, 255, 0, 0, 255, 0)] +// public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) +// { +// var a = new Rgb24(r1, g1, b1); +// var b = new Rgb24(r2, g2, b2); + +// Assert.False(a.Equals(b)); +// Assert.False(a.Equals((object)b)); +// } + +// [Fact] +// public void PackFromRgba32() +// { +// var rgb = default(Rgb24); +// rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + +// Assert.Equal(1, rgb.R); +// Assert.Equal(2, rgb.G); +// Assert.Equal(3, rgb.B); +// } + +// private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( +// r / 255f, +// g / 255f, +// b / 255f, +// a / 255f); + +// [Fact] +// public void PackFromVector4() +// { +// var rgb = default(Rgb24); +// rgb.PackFromVector4(Vec(1, 2, 3, 4)); + +// Assert.Equal(1, rgb.R); +// Assert.Equal(2, rgb.G); +// Assert.Equal(3, rgb.B); +// } + +// [Fact] +// public void ToVector4() +// { +// var rgb = new Rgb24(1, 2, 3); + +// Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); +// } + +// [Fact] +// public void ToRgb24() +// { +// var rgb = new Rgb24(1, 2, 3); +// var dest = default(Rgb24); + +// rgb.ToRgb24(ref dest); + +// Assert.Equal(rgb, dest); +// } + +// [Fact] +// public void ToRgba32() +// { +// var rgb = new Rgb24(1, 2, 3); +// var rgba = default(Rgba32); + +// rgb.ToRgba32(ref rgba); + +// Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); +// } + +// [Fact] +// public void ToBgr24() +// { +// var rgb = new Rgb24(1, 2, 3); +// var bgr = default(Bgr24); + +// rgb.ToBgr24(ref bgr); + +// Assert.Equal(new Bgr24(1, 2, 3), bgr); +// } + +// [Fact] +// public void ToBgra32() +// { +// var rgb = new Rgb24(1, 2, 3); +// var bgra = default(Bgra32); + +// rgb.ToBgra32(ref bgra); + +// Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); +// } + +// [Fact] +// public void Rgb24_PackFromRgb48_ToRgb48() +// { +// // arrange +// var input = default(Rgb24); +// var actual = default(Rgb48); +// var expected = new Rgb48(65535, 0, 65535); + +// // act +// input.PackFromRgb48(expected); +// input.ToRgb48(ref actual); + +// // assert +// Assert.Equal(expected, actual); +// } + +// [Fact] +// public void Rgb24_PackFromRgba64_ToRgba64() +// { +// // arrange +// var input = default(Rgb24); +// var actual = default(Rgba64); +// var expected = new Rgba64(65535, 0, 65535, 65535); + +// // act +// input.PackFromRgba64(expected); +// input.ToRgba64(ref actual); + +// // assert +// Assert.Equal(expected, actual); +// } +// } +//} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 77d6544f00..2af488e3cd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -1,199 +1,192 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.PixelFormats -{ - public class Rgb48Tests - { - [Fact] - public void Rgb48_Values() - { - var rgb = new Rgba64(5243, 9830, 19660, 29491); - - Assert.Equal(5243, rgb.R); - Assert.Equal(9830, rgb.G); - Assert.Equal(19660, rgb.B); - Assert.Equal(29491, rgb.A); - - rgb = new Rgba64(5243 / 65535F, 9830 / 65535F, 19660 / 65535F, 29491 / 65535F); - - Assert.Equal(5243, rgb.R); - Assert.Equal(9830, rgb.G); - Assert.Equal(19660, rgb.B); - Assert.Equal(29491, rgb.A); - } - - [Fact] - public void Rgb48_ToVector4() - { - Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.Zero).ToVector4()); - Assert.Equal(Vector4.One, new Rgb48(Vector3.One).ToVector4()); - } - - [Fact] - public void Rgb48_ToScaledVector4() - { - // arrange - var short2 = new Rgb48(Vector3.One); - - // act - Vector4 actual = short2.ToScaledVector4(); - - // assert - Assert.Equal(1, actual.X); - Assert.Equal(1, actual.Y); - Assert.Equal(1, actual.Z); - Assert.Equal(1, actual.W); - } - - [Fact] - public void Rgb48_PackFromScaledVector4() - { - // arrange - var pixel = default(Rgb48); - var short3 = new Rgb48(Vector3.One); - var expected = new Rgb48(Vector3.One); - - // act - Vector4 scaled = short3.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); - - // assert - Assert.Equal(expected, pixel); - } - - [Fact] - public void Rgb48_Clamping() - { - Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.One * -1234.0f).ToVector4()); - Assert.Equal(Vector4.One, new Rgb48(Vector3.One * 1234.0f).ToVector4()); - } - - [Fact] - public void Rgb48_ToRgb24() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Rgb24); - var expected = new Rgb24(20, 38, 76); - - // act - rgba48.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_ToRgba32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 255); - - // act - rgba48.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_ToArgb32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 76, 255); - - // act - rgba48.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgr24() - { - // arrange - var rgb48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Bgr24); - var expected = new Bgr24(20, 38, 76); - - // act - rgb48.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_ToBgra32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 76, 255); - - // act - rgba48.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgba32_ToRgba32() - { - // arrange - var rgb48 = default(Rgb48); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 255); - - // act - rgb48.PackFromRgba32(expected); - rgb48.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgb48); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgb48); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } - } -} +//// Copyright (c) Six Labors and contributors. +//// Licensed under the Apache License, Version 2.0. + +//using System.Numerics; +//using SixLabors.ImageSharp.PixelFormats; +//using Xunit; + +//namespace SixLabors.ImageSharp.Tests.PixelFormats +//{ +// public class Rgb48Tests +// { +// [Fact] +// public void Rgb48_Values() +// { +// var rgb = new Rgba64(5243, 9830, 19660, 29491); + +// Assert.Equal(5243, rgb.R); +// Assert.Equal(9830, rgb.G); +// Assert.Equal(19660, rgb.B); +// Assert.Equal(29491, rgb.A); +// } + +// [Fact] +// public void Rgb48_ToVector4() +// { +// Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(0, 0, 0, 0).ToVector4()); +// Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); +// } + +// [Fact] +// public void Rgb48_ToScaledVector4() +// { +// // arrange +// var short2 = new Rgb48(Vector3.One); + +// // act +// Vector4 actual = short2.ToScaledVector4(); + +// // assert +// Assert.Equal(1, actual.X); +// Assert.Equal(1, actual.Y); +// Assert.Equal(1, actual.Z); +// Assert.Equal(1, actual.W); +// } + +// [Fact] +// public void Rgb48_PackFromScaledVector4() +// { +// // arrange +// var pixel = default(Rgb48); +// var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); +// var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + +// // act +// Vector4 scaled = short3.ToScaledVector4(); +// pixel.PackFromScaledVector4(scaled); + +// // assert +// Assert.Equal(expected, pixel); +// } + +// //[Fact] +// //public void Rgb48_Clamping() +// //{ +// // Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.One * -1234.0f).ToVector4()); +// // Assert.Equal(Vector4.One, new Rgb48(Vector3.One * 1234.0f).ToVector4()); +// //} + +// //[Fact] +// //public void Rgb48_ToRgb24() +// //{ +// // // arrange +// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Rgb24); +// // var expected = new Rgb24(20, 38, 76); + +// // // act +// // rgba48.ToRgb24(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_ToRgba32() +// //{ +// // // arrange +// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Rgba32); +// // var expected = new Rgba32(20, 38, 76, 255); + +// // // act +// // rgba48.ToRgba32(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_ToArgb32() +// //{ +// // // arrange +// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Argb32); +// // var expected = new Argb32(20, 38, 76, 255); + +// // // act +// // rgba48.ToArgb32(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgba64_ToBgr24() +// //{ +// // // arrange +// // var rgb48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Bgr24); +// // var expected = new Bgr24(20, 38, 76); + +// // // act +// // rgb48.ToBgr24(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_ToBgra32() +// //{ +// // // arrange +// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); +// // var actual = default(Bgra32); +// // var expected = new Bgra32(20, 38, 76, 255); + +// // // act +// // rgba48.ToBgra32(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_PackFromRgba32_ToRgba32() +// //{ +// // // arrange +// // var rgb48 = default(Rgb48); +// // var actual = default(Rgba32); +// // var expected = new Rgba32(20, 38, 76, 255); + +// // // act +// // rgb48.PackFromRgba32(expected); +// // rgb48.ToRgba32(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_PackFromRgb48_ToRgb48() +// //{ +// // // arrange +// // var input = default(Rgb48); +// // var actual = default(Rgb48); +// // var expected = new Rgb48(65535, 0, 65535); + +// // // act +// // input.PackFromRgb48(expected); +// // input.ToRgb48(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} + +// //[Fact] +// //public void Rgb48_PackFromRgba64_ToRgba64() +// //{ +// // // arrange +// // var input = default(Rgb48); +// // var actual = default(Rgba64); +// // var expected = new Rgba64(65535, 0, 65535, 65535); + +// // // act +// // input.PackFromRgba64(expected); +// // input.ToRgba64(ref actual); + +// // // assert +// // Assert.Equal(expected, actual); +// //} +// } +//} diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index fcb3b6c7c8..d8ad6d3f1e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -71,144 +71,144 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba1010102(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Rgba1010102_ToRgb24() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 128); - - // act - rgba.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_ToRgba32() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 128, 0); - - // act - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_ToBgr24() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 128); - - // act - rgba.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_ToBgra32() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(25, 0, 128, 0); - - // act - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgba32_ToRgba32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Rgba32(25, 0, 128, 0); - var actual = default(Rgba32); - - // act - rgba.PackFromRgba32(expected); - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromBgra32_ToBgra32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Bgra32(25, 0, 128, 0); - var actual = default(Bgra32); - - // act - rgba.PackFromBgra32(expected); - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromArgb32_ToArgb32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Argb32(25, 0, 128, 0); - var actual = default(Argb32); - - // act - rgba.PackFromArgb32(expected); - rgba.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgba1010102); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgba1010102); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Rgba1010102_ToRgb24() + //{ + // // arrange + // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgb24); + // var expected = new Rgb24(25, 0, 128); + + // // act + // rgba.ToRgb24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_ToRgba32() + //{ + // // arrange + // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Rgba32); + // var expected = new Rgba32(25, 0, 128, 0); + + // // act + // rgba.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_ToBgr24() + //{ + // // arrange + // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgr24); + // var expected = new Bgr24(25, 0, 128); + + // // act + // rgba.ToBgr24(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_ToBgra32() + //{ + // // arrange + // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + // var actual = default(Bgra32); + // var expected = new Bgra32(25, 0, 128, 0); + + // // act + // rgba.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var rgba = default(Rgba1010102); + // var expected = new Rgba32(25, 0, 128, 0); + // var actual = default(Rgba32); + + // // act + // rgba.PackFromRgba32(expected); + // rgba.ToRgba32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromBgra32_ToBgra32() + //{ + // // arrange + // var rgba = default(Rgba1010102); + // var expected = new Bgra32(25, 0, 128, 0); + // var actual = default(Bgra32); + + // // act + // rgba.PackFromBgra32(expected); + // rgba.ToBgra32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromArgb32_ToArgb32() + //{ + // // arrange + // var rgba = default(Rgba1010102); + // var expected = new Argb32(25, 0, 128, 0); + // var actual = default(Argb32); + + // // act + // rgba.PackFromArgb32(expected); + // rgba.ToArgb32(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromRgb48_ToRgb48() + //{ + // // arrange + // var input = default(Rgba1010102); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + // input.ToRgb48(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba1010102_PackFromRgba64_ToRgba64() + //{ + // // arrange + // var input = default(Rgba1010102); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 65535); + + // // act + // input.PackFromRgba64(expected); + // input.ToRgba64(ref actual); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 4b2c187765..30a5f961b7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -19,12 +19,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreEqual() { - Rgba32 color1 = new Rgba32(0, 0, 0); - Rgba32 color2 = new Rgba32(0, 0, 0, 1F); - Rgba32 color3 = Rgba32.FromHex("#000"); - Rgba32 color4 = Rgba32.FromHex("#000F"); - Rgba32 color5 = Rgba32.FromHex("#000000"); - Rgba32 color6 = Rgba32.FromHex("#000000FF"); + var color1 = new Rgba32(0, 0, 0); + var color2 = new Rgba32(0, 0, 0, 1F); + var color3 = Rgba32.FromHex("#000"); + var color4 = Rgba32.FromHex("#000F"); + var color5 = Rgba32.FromHex("#000000"); + var color6 = Rgba32.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +39,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreNotEqual() { - Rgba32 color1 = new Rgba32(255, 0, 0, 255); - Rgba32 color2 = new Rgba32(0, 0, 0, 255); - Rgba32 color3 = Rgba32.FromHex("#000"); - Rgba32 color4 = Rgba32.FromHex("#000000"); - Rgba32 color5 = Rgba32.FromHex("#FF000000"); + var color1 = new Rgba32(255, 0, 0, 255); + var color2 = new Rgba32(0, 0, 0, 255); + var color3 = Rgba32.FromHex("#000"); + var color4 = Rgba32.FromHex("#000000"); + var color5 = Rgba32.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,25 +57,25 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void ConstructorAssignsProperties() { - Rgba32 color1 = new Rgba32(1, .1f, .133f, .864f); + var color1 = new Rgba32(1, .1f, .133f, .864f); Assert.Equal(255, color1.R); Assert.Equal((byte)Math.Round(.1f * 255), color1.G); Assert.Equal((byte)Math.Round(.133f * 255), color1.B); Assert.Equal((byte)Math.Round(.864f * 255), color1.A); - Rgba32 color2 = new Rgba32(1, .1f, .133f); + var color2 = new Rgba32(1, .1f, .133f); Assert.Equal(255, color2.R); Assert.Equal(Math.Round(.1f * 255), color2.G); Assert.Equal(Math.Round(.133f * 255), color2.B); Assert.Equal(255, color2.A); - Rgba32 color4 = new Rgba32(new Vector3(1, .1f, .133f)); + var color4 = new Rgba32(new Vector3(1, .1f, .133f)); Assert.Equal(255, color4.R); Assert.Equal(Math.Round(.1f * 255), color4.G); Assert.Equal(Math.Round(.133f * 255), color4.B); Assert.Equal(255, color4.A); - Rgba32 color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); + var color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); Assert.Equal(255, color5.R); Assert.Equal(Math.Round(.1f * 255), color5.G); Assert.Equal(Math.Round(.133f * 255), color5.B); @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public unsafe void ByteLayout() { - Rgba32 color = new Rgba32(1, 2, 3, 4); + var color = new Rgba32(1, 2, 3, 4); byte* colorBase = (byte*)&color; Assert.Equal(1, colorBase[0]); Assert.Equal(2, colorBase[1]); @@ -181,23 +181,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba32(Vector4.One * +1234.0f).ToVector4()); } - [Fact] - public void Rgba32_ToRgb24() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(0x1a, 0, 0x80); - - // act - rgba.ToRgb24(ref actual); - - // assert - Assert.Equal(expected.R, actual.R); - Assert.Equal(expected.G, actual.G); - Assert.Equal(expected.B, actual.B); - } - [Fact] public void Rgba32_ToRgba32() { @@ -207,52 +190,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(0x1a, 0, 0x80, 0); // act - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToBgr24() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(0x1a, 0, 0x80); - - // act - rgba.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToBgra32() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToArgb32() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - rgba.ToArgb32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -268,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act rgba.PackFromRgba32(expected); - rgba.ToRgba32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -284,7 +222,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act rgba.PackFromBgra32(expected); - rgba.ToBgra32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -300,14 +238,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act rgba.PackFromArgb32(expected); - rgba.ToArgb32(ref actual); + actual.PackFromRgba32(rgba); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromRgb48_ToRgb48() + public void Rgba32_PackFromRgb48() { // arrange var input = default(Rgba32); @@ -316,14 +254,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromRgba64_ToRgba64() + public void Rgba32_PackFromRgba64() { // arrange var input = default(Rgba32); @@ -332,7 +270,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 92b36a1c62..185fc5635d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -13,33 +13,31 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void Rgba64_PackedValues() { Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(5243, 9830, 19660, 29491).PackedValue); - Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(0.08f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgba = new Rgba64(0x73334CCC2666147B); - Assert.Equal(5243, rgba.R); - Assert.Equal(9830, rgba.G); - Assert.Equal(19660, rgba.B); - Assert.Equal(29491, rgba.A); // Test the limits. - Assert.Equal((ulong)0x0, new Rgba64(Vector4.Zero).PackedValue); - Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64(Vector4.One).PackedValue); + Assert.Equal((ulong)0x0, new Rgba64(0, 0, 0, 0).PackedValue); + Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64( + ushort.MaxValue, + ushort.MaxValue, + ushort.MaxValue, + ushort.MaxValue).PackedValue); + // Test data ordering - Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(((float)0x1EB8) / 0xffff, ((float)0x570A) / 0xffff, ((float)0x8F5C) / 0xffff, ((float)0xC7AD) / 0xffff).PackedValue); - Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(0.12f, 0.34f, 0.56f, 0.78f).PackedValue); + Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(0x1EB8, 0x570A, 0x8F5C, 0xC7AD).PackedValue); } [Fact] public void Rgba64_ToVector4() { - Assert.Equal(Vector4.Zero, new Rgba64(Vector4.Zero).ToVector4()); - Assert.Equal(Vector4.One, new Rgba64(Vector4.One).ToVector4()); + Assert.Equal(Vector4.Zero, new Rgba64(0, 0, 0, 0).ToVector4()); + Assert.Equal(Vector4.One, new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); } [Fact] public void Rgba64_ToScaledVector4() { // arrange - var short2 = new Rgba64(Vector4.One); + var short2 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); // act Vector4 actual = short2.ToScaledVector4(); @@ -56,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { // arrange var pixel = default(Rgba64); - var short4 = new Rgba64(Vector4.One); + var short4 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); const ulong expected = 0xFFFFFFFFFFFFFFFF; // act @@ -71,131 +69,78 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void Rgba64_Clamping() { - Assert.Equal(Vector4.Zero, new Rgba64(Vector4.One * -1234.0f).ToVector4()); - Assert.Equal(Vector4.One, new Rgba64(Vector4.One * 1234.0f).ToVector4()); - } - - [Fact] - public void Rgba64_ToRgb24() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Rgb24); - var expected = new Rgb24(20, 38, 76); - - // act - rgba64.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToRgba32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 115); - - // act - rgba64.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToArgb32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 76, 115); - - // act - rgba64.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgr24() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Bgr24); - var expected = new Bgr24(20, 38, 76); - - // act - rgba64.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgra32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 76, 115); - - // act - rgba64.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_PackFromRgba32_ToRgba32() - { - // arrange - var rgba64 = default(Rgba64); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 115); - - // act - rgba64.PackFromRgba32(expected); - rgba64.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgba64); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); + var zero = default(Rgba64); + var one = default(Rgba64); + zero.PackFromVector4(Vector4.One * -1234.0f); + one.PackFromVector4(Vector4.One * 1234.0f); + Assert.Equal(Vector4.Zero, zero.ToVector4()); + Assert.Equal(Vector4.One, one.ToVector4()); } - [Fact] - public void Rgba64_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgba64); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } + //[Fact] + //public void Rgba64_ToRgba32() + //{ + // // arrange + // var rgba64 = new Rgba64( + // (ushort)(0.08f * ushort.MaxValue), + // (ushort)(0.15f * ushort.MaxValue), + // (ushort)(0.30f * ushort.MaxValue), + // (ushort)(0.45f * ushort.MaxValue)); + // var actual = default(Rgba32); + // var expected = new Rgba32(20, 38, 76, 115); + + // // act + // actual = rgba64.ToRgba32(); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba64_PackFromRgba32_ToRgba32() + //{ + // // arrange + // var rgba64 = default(Rgba64); + // var actual = default(Rgba32); + // var expected = new Rgba32(20, 38, 76, 115); + + // // act + // rgba64.PackFromRgba32(expected); + // actual = rgba64.ToRgba32(); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgb48_PackFromRgb48() + //{ + // // arrange + // var input = default(Rgba64); + // var actual = default(Rgb48); + // var expected = new Rgb48(65535, 0, 65535); + + // // act + // input.PackFromRgb48(expected); + + // // assert + // Assert.Equal(expected, actual); + //} + + //[Fact] + //public void Rgba64_PackFromRgba64() + //{ + // // arrange + // var input = default(Rgba64); + // var actual = default(Rgba64); + // var expected = new Rgba64(65535, 0, 65535, 0); + + // // act + // input.PackFromRgba64(expected); + // actual.PackFromScaledVector4(input.ToScaledVector4()); + + // // assert + // Assert.Equal(expected, actual); + //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index a21b647a74..9b5fceac77 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -19,12 +19,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreEqual() { - RgbaVector color1 = new RgbaVector(0, 0, 0F); - RgbaVector color2 = new RgbaVector(0, 0, 0, 1F); - RgbaVector color3 = RgbaVector.FromHex("#000"); - RgbaVector color4 = RgbaVector.FromHex("#000F"); - RgbaVector color5 = RgbaVector.FromHex("#000000"); - RgbaVector color6 = RgbaVector.FromHex("#000000FF"); + var color1 = new RgbaVector(0, 0, 0F); + var color2 = new RgbaVector(0, 0, 0, 1F); + var color3 = RgbaVector.FromHex("#000"); + var color4 = RgbaVector.FromHex("#000F"); + var color5 = RgbaVector.FromHex("#000000"); + var color6 = RgbaVector.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +39,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreNotEqual() { - RgbaVector color1 = new RgbaVector(1, 0, 0, 1); - RgbaVector color2 = new RgbaVector(0, 0, 0, 1); - RgbaVector color3 = RgbaVector.FromHex("#000"); - RgbaVector color4 = RgbaVector.FromHex("#000000"); - RgbaVector color5 = RgbaVector.FromHex("#FF000000"); + var color1 = new RgbaVector(1, 0, 0, 1); + var color2 = new RgbaVector(0, 0, 0, 1); + var color3 = RgbaVector.FromHex("#000"); + var color4 = RgbaVector.FromHex("#000000"); + var color5 = RgbaVector.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,29 +57,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void ConstructorAssignsProperties() { - RgbaVector color1 = new RgbaVector(1, .1F, .133F, .864F); + var color1 = new RgbaVector(1, .1F, .133F, .864F); Assert.Equal(1F, color1.R); Assert.Equal(.1F, color1.G); Assert.Equal(.133F, color1.B); Assert.Equal(.864F, color1.A); - RgbaVector color2 = new RgbaVector(1, .1f, .133f); + var color2 = new RgbaVector(1, .1f, .133f); Assert.Equal(1F, color2.R); Assert.Equal(.1F, color2.G); Assert.Equal(.133F, color2.B); Assert.Equal(1F, color2.A); - - RgbaVector color4 = new RgbaVector(new Vector3(1, .1f, .133f)); - Assert.Equal(1F, color4.R); - Assert.Equal(.1F, color4.G); - Assert.Equal(.133F, color4.B); - Assert.Equal(1F, color4.A); - - RgbaVector color5 = new RgbaVector(new Vector4(1, .1f, .133f, .5f)); - Assert.Equal(1F, color5.R); - Assert.Equal(.1F, color5.G); - Assert.Equal(.133F, color5.B); - Assert.Equal(.5F, color5.A); } /// @@ -88,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void FromAndToHex() { - RgbaVector color = RgbaVector.FromHex("#AABBCCDD"); + var color = RgbaVector.FromHex("#AABBCCDD"); Assert.Equal(170 / 255F, color.R); Assert.Equal(187 / 255F, color.G); Assert.Equal(204 / 255F, color.B); @@ -116,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void FloatLayout() { - RgbaVector color = new RgbaVector(1F, 2, 3, 4); + var color = new RgbaVector(1F, 2, 3, 4); Vector4 colorBase = Unsafe.As(ref Unsafe.Add(ref color, 0)); float[] ordered = new float[4]; colorBase.CopyTo(ordered); @@ -128,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void RgbaVector_PackFromRgb48_ToRgb48() + public void RgbaVector_PackFromRgb48() { // arrange var input = default(RgbaVector); @@ -137,14 +125,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void RgbaVector_PackFromRgba64_ToRgba64() + public void RgbaVector_PackFromRgba64() { // arrange var input = default(RgbaVector); @@ -153,7 +141,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 5c75fcbbbc..5f2f45b3be 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var pixel = default(Short2); var short2 = new Short2(Vector2.One * 0x7FFF); - ulong expected = 0x7FFF7FFF; + const ulong expected = 0x7FFF7FFF; // act Vector4 scaled = short2.ToScaledVector4(); @@ -79,21 +79,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } - [Fact] - public void Short2_ToRgb24() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Rgb24); - var expected = new Rgb24(128, 127, 0); - - // act - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Short2_ToRgba32() { @@ -103,52 +88,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(128, 127, 0, 255); // act - short2.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToBgr24() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Bgr24); - var expected = new Bgr24(128, 127, 0); - - // act - short2.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToArgb32() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Argb32); - var expected = new Argb32(128, 127, 0, 255); - - // act - short2.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToBgra32() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Bgra32); - var expected = new Bgra32(128, 127, 0, 255); - - // act - short2.ToBgra32(ref actual); + actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -164,14 +104,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short2.PackFromRgba32(expected); - short2.ToRgba32(ref actual); + actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); } [Fact] - public void Short2_PackFromRgb48_ToRgb48() + public void Short2_PackFromRgb48() { // arrange var input = default(Short2); @@ -180,14 +120,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void Short2_PackFromRgba64_ToRgba64() + public void Short2_PackFromRgba64() { // arrange var input = default(Short2); @@ -196,7 +136,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 59dc385d4d..4245fcf381 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var short4 = new Short4(Vector4.One * 0x7FFF); Vector4 scaled = short4.ToScaledVector4(); - long expected = 0x7FFF7FFF7FFF7FFF; + const long expected = 0x7FFF7FFF7FFF7FFF; // act var pixel = default(Short4); @@ -83,36 +83,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One * -0x8000, vector2); } - [Fact] - public void Short4_ToRgb24() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Rgb24); - var expected = new Rgb24(172, 177, 243); - - // act - shortValue.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToBgr24() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Bgr24); - var expected = new Bgr24(172, 177, 243); - - // act - shortValue.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Short4_ToRgba32() { @@ -122,37 +92,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(172, 177, 243, 128); // act - shortValue.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToBgra32() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Bgra32); - var expected = new Bgra32(172, 177, 243, 128); - - // act - shortValue.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToArgb32() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Argb32); - var expected = new Argb32(172, 177, 243, 128); - - // act - shortValue.ToArgb32(ref actual); + actual = shortValue.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -168,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.PackFromRgba32(expected); - short4.ToRgba32(ref actual); + actual = short4.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -184,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); + actual.PackFromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -200,7 +140,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); + actual.PackFromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -216,7 +156,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -232,7 +172,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + actual.PackFromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 1fca398fcd..29c97ce35f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Bytes_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Vector4_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); - var colorVector = new RgbaVector(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Vector3_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); - var colorVector = new RgbaVector(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -73,76 +73,28 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_To_Vector4_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.ToVector4(), colorVector.ToVector4()); } - [Fact] - public void Color_Types_To_RgbBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var rgb = default(Rgb24); - var rgbVector = default(Rgb24); - - color.ToRgb24(ref rgb); - colorVector.ToRgb24(ref rgbVector); - - Assert.Equal(rgb, rgbVector); - } - [Fact] public void Color_Types_To_RgbaBytes_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var rgba = default(Rgba32); - var rgbaVector = default(Rgba32); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - color.ToRgba32(ref rgba); - colorVector.ToRgba32(ref rgbaVector); + var rgba = color.ToRgba32(); + var rgbaVector = colorVector.ToRgba32(); Assert.Equal(rgba, rgbaVector); } - [Fact] - public void Color_Types_To_BgrBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var bgr = default(Bgr24); - var bgrVector = default(Bgr24); - - color.ToBgr24(ref bgr); - colorVector.ToBgr24(ref bgrVector); - - Assert.Equal(bgr, bgrVector); - } - - [Fact] - public void Color_Types_To_BgraBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var bgra = default(Bgra32); - var bgraVector = default(Bgra32); - - color.ToBgra32(ref bgra); - colorVector.ToBgra32(ref bgraVector); - - Assert.Equal(bgra, bgraVector); - } - [Fact] public void Color_Types_To_Hex_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); // 183060C0 Assert.Equal(color.ToHex(), colorVector.ToHex()); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index edc6994e7a..17240839db 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -65,10 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms nameof(KnownResamplers.Lanczos8), }; - public AffineTransformTests(ITestOutputHelper output) - { - this.Output = output; - } + public AffineTransformTests(ITestOutputHelper output) => this.Output = output; /// /// The output of an "all white" image should be "all white" or transparent, regardless of the transformation and the resampler. @@ -240,12 +237,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms where TPixel : struct, IPixel { Span data = image.Frames.RootFrame.GetPixelSpan(); - var rgba = default(Rgba32); var white = new Rgb24(255, 255, 255); foreach (TPixel pixel in data) { - pixel.ToRgba32(ref rgba); - if (rgba.A == 0) continue; + var rgba = pixel.ToRgba32(); + if (rgba.A == 0) + { + continue; + } Assert.Equal(white, rgba.Rgb); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index c2b1c26c54..719e9793a0 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -97,12 +97,11 @@ namespace SixLabors.ImageSharp.Tests { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; - var trans = default(Rgba32); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - quantized.Palette[i].ToRgba32(ref trans); + var trans = quantized.Palette[i].ToRgba32(); - if (trans.Equals(default(Rgba32))) + if (trans.Equals(default)) { index = i; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 65b32e0880..70b630adf1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -72,7 +72,10 @@ namespace SixLabors.ImageSharp.Tests extension = '.' + extension; } - if (fn != string.Empty) fn = '_' + fn; + if (fn != string.Empty) + { + fn = '_' + fn; + } string pixName = ""; @@ -274,17 +277,14 @@ namespace SixLabors.ImageSharp.Tests } public static void ModifyPixel(Image img, int x, int y, byte perChannelChange) - where TPixel : struct, IPixel - { - ModifyPixel(img.Frames.RootFrame, x, y, perChannelChange); - } + where TPixel : struct, IPixel => ModifyPixel(img.Frames.RootFrame, x, y, perChannelChange); public static void ModifyPixel(ImageFrame img, int x, int y, byte perChannelChange) where TPixel : struct, IPixel { TPixel pixel = img[x, y]; Rgba64 rgbaPixel = default; - pixel.ToRgba64(ref rgbaPixel); + rgbaPixel.PackFromScaledVector4(pixel.ToScaledVector4()); ushort change = (ushort)Math.Round((perChannelChange / 255F) * 65535F); if (rgbaPixel.R + perChannelChange <= 255) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 5a14f2e26e..e6a5ffc84b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -80,10 +80,10 @@ namespace SixLabors.ImageSharp.Tests } else { - ca.ToRgb24(ref rgb1); - cb.ToRgb24(ref rgb2); + rgb1 = ca.ToRgba32().Rgb; + rgb2 = cb.ToRgba32().Rgb; - if (rgb1.R != rgb2.R || rgb1.G != rgb2.G || rgb1.B != rgb2.B) + if (!rgb1.Equals(rgb2)) { return false; } @@ -94,10 +94,7 @@ namespace SixLabors.ImageSharp.Tests return true; } - public static string ToCsv(this IEnumerable items, string separator = ",") - { - return String.Join(separator, items.Select(o => String.Format(CultureInfo.InvariantCulture, "{0}", o))); - } + public static string ToCsv(this IEnumerable items, string separator = ",") => string.Join(separator, items.Select(o => string.Format(CultureInfo.InvariantCulture, "{0}", o))); public static Type GetClrType(this PixelTypes pixelType) => PixelTypes2ClrTypes[pixelType]; @@ -141,10 +138,7 @@ namespace SixLabors.ImageSharp.Tests internal static PixelTypes[] GetAllPixelTypes() => (PixelTypes[])Enum.GetValues(typeof(PixelTypes)); internal static TPixel GetPixelOfNamedColor(string colorName) - where TPixel : struct, IPixel - { - return (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null); - } + where TPixel : struct, IPixel => (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null); /// /// Utility for testing image processor extension methods: diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 5305eb2ba3..1d284af15e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -2,36 +2,26 @@ // Licensed under the Apache License, Version 2.0. using System; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; -using Xunit.Abstractions; - using System.Collections.Concurrent; using System.IO; - using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests { - using SixLabors.Memory; - public class TestImageProviderTests { - public TestImageProviderTests(ITestOutputHelper output) - { - this.Output = output; - } + public TestImageProviderTests(ITestOutputHelper output) => this.Output = output; private ITestOutputHelper Output { get; } [Theory] [WithBlankImages(1, 1, PixelTypes.Rgba32)] public void NoOutputSubfolderIsPresentByDefault(TestImageProvider provider) - where TPixel : struct, IPixel - { - Assert.Empty(provider.Utility.OutputSubfolderName); - } + where TPixel : struct, IPixel => Assert.Empty(provider.Utility.OutputSubfolderName); [Theory] [WithBlankImages(42, 666, PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.HalfSingle, "hello")] @@ -64,10 +54,7 @@ namespace SixLabors.ImageSharp.Tests [WithBlankImages(1, 1, PixelTypes.Alpha8, PixelTypes.Alpha8)] [WithBlankImages(1, 1, PixelTypes.Argb32, PixelTypes.Argb32)] public void PixelType_PropertyValueIsCorrect(TestImageProvider provider, PixelTypes expected) - where TPixel : struct, IPixel - { - Assert.Equal(expected, provider.PixelType); - } + where TPixel : struct, IPixel => Assert.Equal(expected, provider.PixelType); [Theory] [WithFile(TestImages.Bmp.Car, PixelTypes.All, 88)] @@ -96,7 +83,7 @@ namespace SixLabors.ImageSharp.Tests // Couldn't make xUnit happy without this hackery: - private static ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); private string callerName = null; @@ -160,7 +147,7 @@ namespace SixLabors.ImageSharp.Tests return new Image(42, 42); } - private static ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); private string callerName = null; @@ -287,14 +274,12 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(10, img.Width); Assert.Equal(20, img.Height); - var rgba = default(Rgba32); - Buffer2D pixels = img.GetRootFramePixelBuffer(); for (int y = 0; y < pixels.Height; y++) { for (int x = 0; x < pixels.Width; x++) { - pixels[x, y].ToRgba32(ref rgba); + var rgba = pixels[x, y].ToRgba32(); Assert.Equal(255, rgba.R); Assert.Equal(100, rgba.G); @@ -311,10 +296,7 @@ namespace SixLabors.ImageSharp.Tests /// /// public static Image CreateTestImage() - where TPixel : struct, IPixel - { - return new Image(3, 3); - } + where TPixel : struct, IPixel => new Image(3, 3); [Theory] [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All)] From d4327c51290f1809e32a202b47c5f8f490d16375 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 10 Oct 2018 08:58:22 +0100 Subject: [PATCH 010/238] Fix linear gradient brush test. --- .../Drawing/FillLinearGradientBrushTests.cs | 37 ++++++++++--------- tests/Images/External | 2 +- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index 3522ade7c4..74a61dfbaa 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -283,10 +283,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing { // it's diagonal, so for any (a, a) on the gradient line, for all (a-x, b+x) - +/- depending on the diagonal direction - must be the same color) TPixel colorOnDiagonal = image[i, i]; + + // TODO: This is incorrect. from -0 to < 0 ?? int orthoCount = 0; for (int offset = -orthoCount; offset < orthoCount; offset++) { - Assert.Equal(colorOnDiagonal, image[i + horizontalSign * offset, i + verticalSign * offset]); + Assert.Equal(colorOnDiagonal, image[i + (horizontalSign * offset), i + (verticalSign * offset)]); } } @@ -302,8 +304,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing [Theory] [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .2f, .5f, .9f }, new[] { 0, 0, 1, 1 })] [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 499, 499, 0, new[] { 0f, 0.2f, 0.5f, 0.9f }, new[] { 0, 1, 2, 3 })] - [WithBlankImages(500, 500, PixelTypes.Rgba32, 499, 499, 0, 0, new[] { 0f, 0.7f, 0.8f, 0.9f}, new[] { 0, 1, 2, 0 })] - [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .5f, 1f}, new[]{0, 1, 3})] + [WithBlankImages(500, 500, PixelTypes.Rgba32, 499, 499, 0, 0, new[] { 0f, 0.7f, 0.8f, 0.9f }, new[] { 0, 1, 2, 0 })] + [WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .5f, 1f }, new[] { 0, 1, 3 })] public void ArbitraryGradients( TestImageProvider provider, int startX, int startY, @@ -312,35 +314,36 @@ namespace SixLabors.ImageSharp.Tests.Drawing int[] stopColorCodes) where TPixel : struct, IPixel { - TPixel[] colors = { - NamedColors.Navy, NamedColors.LightGreen, NamedColors.Yellow, - NamedColors.Red - }; + TPixel[] colors = + { + NamedColors.Navy, NamedColors.LightGreen, NamedColors.Yellow, + NamedColors.Red + }; var coloringVariant = new StringBuilder(); - ColorStop[] colorStops = new ColorStop[stopPositions.Length]; + var colorStops = new ColorStop[stopPositions.Length]; for (int i = 0; i < stopPositions.Length; i++) { TPixel color = colors[stopColorCodes[i % colors.Length]]; float position = stopPositions[i]; colorStops[i] = new ColorStop(position, color); - coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color, position); + coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color.ToRgba32().ToHex(), position); } FormattableString variant = $"({startX},{startY})_TO_({endX},{endY})__[{coloringVariant}]"; provider.VerifyOperation( image => - { - var unicolorLinearGradientBrush = new LinearGradientBrush( - new SixLabors.Primitives.Point(startX, startY), - new SixLabors.Primitives.Point(endX, endY), - GradientRepetitionMode.None, - colorStops); + { + var unicolorLinearGradientBrush = new LinearGradientBrush( + new SixLabors.Primitives.Point(startX, startY), + new SixLabors.Primitives.Point(endX, endY), + GradientRepetitionMode.None, + colorStops); - image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); - }, + image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); + }, variant, false, false); diff --git a/tests/Images/External b/tests/Images/External index 03c7fa7582..1a807d17b4 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 03c7fa7582dea75cea0d49514ccb7e1b6dc9e780 +Subproject commit 1a807d17b4cf5ab50558983d4137614cabe96ce3 From c349c2b248e6740d23bf3e82af4c7d99c2d8cf31 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 13 Oct 2018 16:55:17 +0100 Subject: [PATCH 011/238] Fix up Gray8 and Gary16 tests --- .../PixelFormats/Gray16Tests.cs | 296 +++++++----------- .../PixelFormats/Gray8Tests.cs | 248 +++++---------- 2 files changed, 189 insertions(+), 355 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index 166fb230ac..db4fa70197 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -15,197 +15,115 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [InlineData(32767)] [InlineData(42)] public void Gray16_PackedValue_EqualsInput(ushort input) + => Assert.Equal(input, new Gray16(input).PackedValue); + + [Fact] + public void Gray16_PackFromScaledVector4() + { + // Arrange + Gray16 gray = default; + const ushort expected = 32767; + Vector4 scaled = new Gray16(expected).ToScaledVector4(); + + // Act + gray.PackFromScaledVector4(scaled); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToScaledVector4(ushort input) + { + // Arrange + var gray = new Gray16(input); + + // Act + Vector4 actual = gray.ToScaledVector4(); + + // Assert + float vectorInput = input / 65535F; + Assert.Equal(vectorInput, actual.X); + Assert.Equal(vectorInput, actual.Y); + Assert.Equal(vectorInput, actual.Z); + Assert.Equal(1F, actual.W); + } + + [Fact] + public void Gray16_PackFromVector4() + { + // Arrange + Gray16 gray = default; + const ushort expected = 32767; + var vector = new Gray16(expected).ToVector4(); + + // Act + gray.PackFromVector4(vector); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToVector4(ushort input) { - Assert.Equal(input, new Gray16(input).PackedValue); + // Arrange + var gray = new Gray16(input); + + // Act + var actual = gray.ToVector4(); + + // Assert + float vectorInput = input / 65535F; + Assert.Equal(vectorInput, actual.X); + Assert.Equal(vectorInput, actual.Y); + Assert.Equal(vectorInput, actual.Z); + Assert.Equal(1F, actual.W); } - //[Theory] - //[InlineData(0)] - //[InlineData(65535)] - //[InlineData(32767)] - //public void Gray16_ToVector4(ushort input) - //{ - // // arrange - // var gray = new Gray16(input); - - // // act - // var actual = gray.ToVector4(); - - // // assert - // Assert.Equal(input, actual.X); - // Assert.Equal(input, actual.Y); - // Assert.Equal(input, actual.Z); - // Assert.Equal(1, actual.W); - //} - - //[Theory] - //[InlineData(0)] - //[InlineData(65535)] - //[InlineData(32767)] - //public void Gray16_ToScaledVector4(ushort input) - //{ - // // arrange - // var gray = new Gray16(input); - - // // act - // var actual = gray.ToScaledVector4(); - - // // assert - // float scaledInput = input / 65535f; - // Assert.Equal(scaledInput, actual.X); - // Assert.Equal(scaledInput, actual.Y); - // Assert.Equal(scaledInput, actual.Z); - // Assert.Equal(1, actual.W); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4() - //{ - // // arrange - // Gray16 gray = default; - // int expected = 32767; - // Vector4 scaled = new Gray16((ushort)expected).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // ushort actual = gray.PackedValue; - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToRgb24() - //{ - // // arrange - // Rgb24 actual = default; - // Gray16 gray = default; - // var expected = new Rgb24(128, 128, 128); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToRgba32() - //{ - // // arrange - // Rgba32 actual = default; - // Gray16 gray = default; - // var expected = new Rgba32(128, 128, 128, 255); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToBgr24() - //{ - // // arrange - // Bgr24 actual = default; - // Gray16 gray = default; - // var expected = new Bgr24(128, 128, 128); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToBgra32() - //{ - // // arrange - // Bgra32 actual = default; - // Gray16 gray = default; - // var expected = new Bgra32(128,128,128); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToArgb32() - //{ - // // arrange - // Gray16 gray = default; - // Argb32 actual = default; - // var expected = new Argb32(128, 128, 128); - // Vector4 scaled = new Gray16(32768).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromScaledVector4_ToRgba64() - //{ - // // arrange - // Gray16 gray = default; - // Rgba64 actual = default; - // var expected = new Rgba64(65535, 65535, 65535, 65535); - // Vector4 scaled = new Gray16(65535).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var gray = default(Gray16); - // var actual = default(Rgb48); - // var expected = new Rgb48(0, 0, 0); - - // // act - // gray.PackFromRgb48(expected); - // gray.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray16_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var gray = default(Gray16); - // var actual = default(Rgba64); - // var expected = new Rgba64(0, 0, 0, 65535); - - // // act - // gray.PackFromRgba64(expected); - // gray.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} + [Fact] + public void Gray16_PackFromRgba32() + { + // Arrange + Gray16 gray = default; + const byte rgb = 128; + ushort scaledRgb = ImageMaths.UpscaleFrom8BitTo16Bit(rgb); + ushort expected = ImageMaths.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); + + // Act + gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(8100)] + public void Gray16_ToRgba32(ushort input) + { + // Arrange + ushort expected = ImageMaths.DownScaleFrom16BitTo8Bit(input); + var gray = new Gray16(input); + + // Act + var actual = gray.ToRgba32(); + + // Assert + Assert.Equal(expected, actual.R); + Assert.Equal(expected, actual.G); + Assert.Equal(expected, actual.B); + Assert.Equal(byte.MaxValue, actual.A); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index ae114a0e26..aaca6c8776 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -15,28 +15,23 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [InlineData(10)] [InlineData(42)] public void Gray8_PackedValue_EqualsInput(byte input) + => Assert.Equal(input, new Gray8(input).PackedValue); + + [Fact] + public void Gray8_PackFromScaledVector4() { - Assert.Equal(input, new Gray8(input).PackedValue); - } + // Arrange + Gray8 gray = default; + const byte expected = 128; + Vector4 scaled = new Gray8(expected).ToScaledVector4(); - //[Theory] - //[InlineData(0, 0)] - //[InlineData(255, 1)] - //[InlineData(30)] - //public void Gray8_ToVector4(byte input) - //{ - // // arrange - // var gray = new Gray8(input); - - // // act - // var actual = gray.ToVector4(); - - // // assert - // Assert.Equal(input, actual.X); - // Assert.Equal(input, actual.Y); - // Assert.Equal(input, actual.Z); - // Assert.Equal(1, actual.W); - //} + // Act + gray.PackFromScaledVector4(scaled); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } [Theory] [InlineData(0)] @@ -44,14 +39,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [InlineData(30)] public void Gray8_ToScaledVector4(byte input) { - // arrange + // Arrange var gray = new Gray8(input); - // act - var actual = gray.ToScaledVector4(); + // Act + Vector4 actual = gray.ToScaledVector4(); - // assert - float scaledInput = input / 255f; + // Assert + float scaledInput = input / 255F; Assert.Equal(scaledInput, actual.X); Assert.Equal(scaledInput, actual.Y); Assert.Equal(scaledInput, actual.Z); @@ -59,153 +54,74 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray8_PackFromScaledVector4() + public void Gray8_PackFromVector4() { - // arrange + // Arrange Gray8 gray = default; - int expected = 128; - Vector4 scaled = new Gray8(128).ToScaledVector4(); + const int expected = 128; + var vector = new Gray8(expected).ToVector4(); - // act - gray.PackFromScaledVector4(scaled); + // Act + gray.PackFromVector4(vector); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToVector4(byte input) + { + // Arrange + var gray = new Gray8(input); + + // Act + var actual = gray.ToVector4(); + + // Assert + float scaledInput = input / 255F; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Fact] + public void Gray8_PackFromRgba32() + { + // Arrange + Gray8 gray = default; + const byte rgb = 128; + byte expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb); + + // Act + gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); byte actual = gray.PackedValue; - // assert + // Assert Assert.Equal(expected, actual); } - //[Fact] - //public void Gray8_PackFromScaledVector4_ToRgb24() - //{ - // // arrange - // Rgb24 actual = default; - // Gray8 gray = default; - // var expected = new Rgb24(128, 128, 128); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToRgba32() - //{ - // // arrange - // Rgba32 actual = default; - // Gray8 gray = default; - // var expected = new Rgba32(128, 128, 128, 255); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToBgr24() - //{ - // // arrange - // Bgr24 actual = default; - // Gray8 gray = default; - // var expected = new Bgr24(128, 128, 128); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToBgra32() - //{ - // // arrange - // Bgra32 actual = default; - // Gray8 gray = default; - // var expected = new Bgra32(128,128,128); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToArgb32() - //{ - // // arrange - // Gray8 gray = default; - // Argb32 actual = default; - // var expected = new Argb32(128, 128, 128); - // Vector4 scaled = new Gray8(128).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromScaledVector4_ToRgba64() - //{ - // // arrange - // Gray8 gray = default; - // Rgba64 actual = default; - // var expected = new Rgba64(65535, 65535, 65535, 65535); - // Vector4 scaled = new Gray8(255).ToScaledVector4(); - - // // act - // gray.PackFromScaledVector4(scaled); - // gray.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var gray = default(Gray8); - // var actual = default(Rgb48); - // var expected = new Rgb48(0, 0, 0); - - // // act - // gray.PackFromRgb48(expected); - // gray.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Gray8_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var gray = default(Gray8); - // var actual = default(Rgba64); - // var expected = new Rgba64(0, 0, 0, 65535); - - // // act - // gray.PackFromRgba64(expected); - // gray.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(30)] + public void Gray8_ToRgba32(byte input) + { + // Arrange + var gray = new Gray8(input); + + // Act + var actual = gray.ToRgba32(); + + // Assert + Assert.Equal(input, actual.R); + Assert.Equal(input, actual.G); + Assert.Equal(input, actual.B); + Assert.Equal(byte.MaxValue, actual.A); + } } -} +} \ No newline at end of file From 1f7df77c5c72acae8fc5ca32d5604ece8a26fb24 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 13 Oct 2018 17:36:12 +0100 Subject: [PATCH 012/238] Fix up pixel format tests --- .../PixelFormats/Argb32Tests.cs | 155 ---------- .../PixelFormats/Bgr24Tests.cs | 76 ----- .../PixelFormats/Bgr565Tests.cs | 107 ------- .../PixelFormats/Bgra32Tests.cs | 76 ----- .../PixelFormats/Bgra4444Tests.cs | 155 ---------- .../PixelFormats/Bgra5551Tests.cs | 155 ---------- .../PixelFormats/Byte4Tests.cs | 155 ---------- .../PixelFormats/HalfSingleTests.cs | 107 ------- .../PixelFormats/HalfVector2Tests.cs | 107 ------- .../PixelFormats/HalfVector4Tests.cs | 155 ---------- .../PixelFormats/NormalizedByte2Tests.cs | 123 -------- .../PixelFormats/NormalizedByte4Tests.cs | 140 --------- .../PixelFormats/NormalizedShort2Tests.cs | 124 -------- .../PixelFormats/NormalizedShort4Tests.cs | 142 +-------- .../PixelFormats/Rg32Tests.cs | 92 ------ .../PixelFormats/Rgb24Tests.cs | 287 +++++++----------- .../PixelFormats/Rgb48Tests.cs | 253 ++++----------- .../PixelFormats/Rgba1010102Tests.cs | 148 +-------- .../PixelFormats/Rgba64Tests.cs | 75 +---- tests/Images/External | 2 +- 20 files changed, 198 insertions(+), 2436 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 53545f517a..6186793c5b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -66,160 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Argb32(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()); } - - //[Fact] - //public void Argb32_ToRgb24() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(0x1a, 0, 0x80); - - // // act - // argb.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_ToRgba32() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // // act - // argb.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_ToBgr24() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(0x1a, 0, 0x80); - - // // act - // argb.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_ToBgra32() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // // act - // argb.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_ToArgb32() - //{ - // // arrange - // var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(0x1a, 0, 0x80, 0); - - // // act - // argb.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Rgba32); - // var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // // act - // argb.PackFromRgba32(expected); - // argb.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Bgra32); - // var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // // act - // argb.PackFromBgra32(expected); - // argb.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Argb32); - // var expected = new Argb32(0x1a, 0, 0x80, 0); - - // // act - // argb.PackFromArgb32(expected); - // argb.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // argb.PackFromRgb48(expected); - // argb.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Argb32_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var argb = default(Argb32); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // argb.PackFromRgba64(expected); - // argb.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index e742789e4d..96589a03e0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -95,81 +95,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } - - //[Fact] - //public void ToRgb24() - //{ - // var rgb = new Bgr24(1, 2, 3); - // var dest = default(Rgb24); - - // rgb.ToRgb24(ref dest); - - // Assert.Equal(new Rgb24(1, 2, 3), dest); - //} - - //[Fact] - //public void ToRgba32() - //{ - // var rgb = new Bgr24(1, 2, 3); - // var rgba = default(Rgba32); - - // rgb.ToRgba32(ref rgba); - - // Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); - //} - - //[Fact] - //public void ToBgr24() - //{ - // var rgb = new Bgr24(1, 2, 3); - // var bgr = default(Bgr24); - - // rgb.ToBgr24(ref bgr); - - // Assert.Equal(new Bgr24(1, 2, 3), bgr); - //} - - //[Fact] - //public void ToBgra32() - //{ - // var rgb = new Bgr24(1, 2, 3); - // var bgra = default(Bgra32); - - // rgb.ToBgra32(ref bgra); - - // Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - //} - - //[Fact] - //public void Bgr24_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgr24); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr24_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgr24); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 6954067a34..8cbbf558d8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -69,112 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector3.Zero, new Bgr565(Vector3.One * -1234F).ToVector3()); Assert.Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()); } - - //[Fact] - //public void Bgr565_ToRgb24() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Rgb24); - // var expected = new Rgb24(25, 0, 132); - - // // act - // bgra.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_ToRgba32() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Rgba32); - // var expected = new Rgba32(25, 0, 132, 255); - - // // act - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_ToBgr24() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Bgr24); - // var expected = new Bgr24(25, 0, 132); - - // // act - // bgra.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_ToBgra32() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Bgra32); - // var expected = new Bgra32(25, 0, 132, 255); - - // // act - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_ToArgb32() - //{ - // // arrange - // var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - // var actual = default(Argb32); - // var expected = new Argb32(25, 0, 132, 255); - - // // act - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgr565); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgr565_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgr565); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 9ff84a88c1..1b890ac494 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -102,81 +102,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); } - - //[Fact] - //public void ToRgb24() - //{ - // var c = new Bgra32(1, 2, 3, 4); - // var dest = default(Rgb24); - - // c.ToRgb24(ref dest); - - // Assert.Equal(new Rgb24(1, 2, 3), dest); - //} - - //[Fact] - //public void ToRgba32() - //{ - // var c = new Bgra32(1, 2, 3, 4); - // var rgba = default(Rgba32); - - // c.ToRgba32(ref rgba); - - // Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); - //} - - //[Fact] - //public void ToBgr24() - //{ - // var rgb = new Bgra32(1, 2, 3, 4); - // var bgr = default(Bgr24); - - // rgb.ToBgr24(ref bgr); - - // Assert.Equal(new Bgr24(1, 2, 3), bgr); - //} - - //[Fact] - //public void ToBgra32() - //{ - // var rgb = new Bgra32(1, 2, 3, 4); - // var bgra = default(Bgra32); - - // rgb.ToBgra32(ref bgra); - - // Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); - //} - - //[Fact] - //public void Bgra32_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgra32); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra32_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgra32); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 2e6e339b6a..a2fc1a0520 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -70,160 +70,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Bgra4444(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4()); } - - //[Fact] - //public void Bgra4444_ToRgb24() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(34, 0, 136); - - // // act - // bgra.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_ToRgba32() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(34, 0, 136, 0); - - // // act - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_ToBgr24() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(34, 0, 136); - - // // act - // bgra.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_ToBgra32() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(34, 0, 136, 0); - - // // act - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_ToArgb32() - //{ - // // arrange - // var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(34, 0, 136, 0); - - // // act - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var bgra = default(Bgra4444); - // var actual = default(Rgba32); - // var expected = new Rgba32(34, 0, 136, 0); - - // // act - // bgra.PackFromRgba32(expected); - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var bgra = default(Bgra4444); - // var actual = default(Bgra32); - // var expected = new Bgra32(34, 0, 136, 0); - - // // act - // bgra.PackFromBgra32(expected); - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var bgra = default(Bgra4444); - // var actual = default(Argb32); - // var expected = new Argb32(34, 0, 136, 0); - - // // act - // bgra.PackFromArgb32(expected); - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgra4444); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra4444_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgra4444); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index 3a0aec3209..084dfbd97c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -69,160 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Bgra5551(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4()); } - - //[Fact] - //public void Bgra5551_ToRgb24() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(24, 0, 131); - - // // act - // bgra.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_Rgba32() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(24, 0, 131, 0); - - // // act - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_ToBgr24() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(24, 0, 131); - - // // act - // bgra.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_Bgra32() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(24, 0, 131, 0); - - // // act - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_ToArgb32() - //{ - // // arrange - // var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(24, 0, 131, 0); - - // // act - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var bgra = default(Bgra5551); - // var expected = new Rgba32(24, 0, 131, 0); - // var actual = default(Rgba32); - - // // act - // bgra.PackFromRgba32(expected); - // bgra.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var bgra = default(Bgra5551); - // var expected = new Bgra32(24, 0, 131, 0); - // var actual = default(Bgra32); - - // // act - // bgra.PackFromBgra32(expected); - // bgra.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var bgra = default(Bgra5551); - // var expected = new Argb32(24, 0, 131, 0); - // var actual = default(Argb32); - - // // act - // bgra.PackFromArgb32(expected); - // bgra.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Bgra5551); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Bgra5551_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Bgra5551); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index d1e8cceaa4..de1c749f6c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -67,160 +67,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Byte4(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4()); } - - //[Fact] - //public void Byte4_ToRgb24() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(128, 0, 0); - - // // act - // byte4.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_Rgba32() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(128, 0, 0, 0); - - // // act - // byte4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_ToBgr24() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(128, 0, 0); - - // // act - // byte4.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_Bgra32() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(128, 0, 0, 0); - - // // act - // byte4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_Argb32() - //{ - // // arrange - // var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(128, 0, 0, 0); - - // // act - // byte4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var byte4 = default(Byte4); - // var actual = default(Rgba32); - // var expected = new Rgba32(20, 38, 0, 255); - - // // act - // byte4.PackFromRgba32(expected); - // byte4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var byte4 = default(Byte4); - // var actual = default(Bgra32); - // var expected = new Bgra32(20, 38, 0, 255); - - // // act - // byte4.PackFromBgra32(expected); - // byte4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var byte4 = default(Byte4); - // var actual = default(Argb32); - // var expected = new Argb32(20, 38, 0, 255); - - // // act - // byte4.PackFromArgb32(expected); - // byte4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Byte4); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Byte4_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Byte4); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 1c3905854e..fed55af6f7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -66,112 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void HalfSingle_ToRgb24() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Rgb24); - // var expected = new Rgb24(128, 0, 0); - - // // act - // halfVector.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_Rgba32() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Rgba32); - // var expected = new Rgba32(128, 0, 0, 255); - - // // act - // halfVector.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_ToBgr24() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Bgr24); - // var expected = new Bgr24(128, 0, 0); - - // // act - // halfVector.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_Bgra32() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Bgra32); - // var expected = new Bgra32(128, 0, 0, 255); - - // // act - // halfVector.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_Argb32() - //{ - // // arrange - // var halfVector = new HalfSingle(.5F); - // var actual = default(Argb32); - // var expected = new Argb32(128, 0, 0, 255); - - // // act - // halfVector.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(HalfSingle); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfSingle_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(HalfSingle); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index 1ceb224e5e..c775e3a0de 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -71,112 +71,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void HalfVector2_ToRgb24() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Rgb24); - // var expected = new Rgb24(128, 64, 0); - - // // act - // halfVector.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_Rgba32() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Rgba32); - // var expected = new Rgba32(128, 64, 0, 255); - - // // act - // halfVector.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_ToBgr24() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Bgr24); - // var expected = new Bgr24(128, 64, 0); - - // // act - // halfVector.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_Bgra32() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Bgra32); - // var expected = new Bgra32(128, 64, 0, 255); - - // // act - // halfVector.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_Argb32() - //{ - // // arrange - // var halfVector = new HalfVector2(.5F, .25F); - // var actual = default(Argb32); - // var expected = new Argb32(128, 64, 0, 255); - - // // act - // halfVector.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(HalfVector2); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector2_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(HalfVector2); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 3ba5718503..540a1ed08b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -65,160 +65,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void HalfVector4_ToRgb24() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Rgb24); - // var expected = new Rgb24(64, 128, 191); - - // // act - // halfVector.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_Rgba32() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Rgba32); - // var expected = new Rgba32(64, 128, 191, 255); - - // // act - // halfVector.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_ToBgr24() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Bgr24); - // var expected = new Bgr24(64, 128, 191); - - // // act - // halfVector.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_Bgra32() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Bgra32); - // var expected = new Bgra32(64, 128, 191, 255); - - // // act - // halfVector.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_Argb32() - //{ - // // arrange - // var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - // var actual = default(Argb32); - // var expected = new Argb32(64, 128, 191, 255); - - // // act - // halfVector.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var halVector = default(HalfVector4); - // var actual = default(Rgba32); - // var expected = new Rgba32(64, 128, 191, 255); - - // // act - // halVector.PackFromRgba32(expected); - // halVector.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var halVector = default(HalfVector4); - // var actual = default(Bgra32); - // var expected = new Bgra32(64, 128, 191, 255); - - // // act - // halVector.PackFromBgra32(expected); - // halVector.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var halVector = default(HalfVector4); - // var actual = default(Argb32); - // var expected = new Argb32(64, 128, 191, 255); - - // // act - // halVector.PackFromArgb32(expected); - // halVector.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(HalfVector4); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void HalfVector4_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(HalfVector4); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 3ab36853b9..98b747a94f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -66,128 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void NormalizedByte2_PackFromRgba32() - //{ - // // arrange - // var byte2 = new NormalizedByte2(); - // var rgba = new Rgba32(141, 90, 0, 0); - // int expected = 0xda0d; - - // // act - // byte2.PackFromRgba32(rgba); - // ushort actual = byte2.PackedValue; - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToRgb24() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Rgb24); - // var expected = new Rgb24(141, 90, 0); - - // // act - // short4.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToRgba32() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Rgba32); - // var expected = new Rgba32(141, 90, 0, 255); - - // // act - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToBgr24() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Bgr24); - // var expected = new Bgr24(141, 90, 0); - - // // act - // short4.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToBgra32() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Bgra32); - // var expected = new Bgra32(141, 90, 0, 255); - - // // act - // short4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_ToArgb32() - //{ - // // arrange - // var short4 = new NormalizedByte2(0.1f, -0.3f); - // var actual = default(Argb32); - // var expected = new Argb32(141, 90, 0, 255); - - // // act - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(NormalizedByte2); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte2_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(NormalizedByte2); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index acac04853f..d9cca360b2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -60,145 +60,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void NormalizedByte4_ToRgb24() - //{ - // // arrange - // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(141, 90, 192); - - // // act - // short4.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_ToRgba32() - //{ - // // arrange - // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(141, 90, 192, 39); - - // // act - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_ToBgr24() - //{ - // // arrange - // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(141, 90, 192); - - // // act - // short4.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_ToArgb32() - //{ - // // arrange - // var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(141, 90, 192, 39); - - // // act - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedByte4); - // var actual = default(Rgba32); - // var expected = new Rgba32(9, 115, 202, 127); - - // // act - // short4.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromBgra32_ToRgba32() - //{ - // // arrange - // var actual = default(Bgra32); - // var short4 = default(NormalizedByte4); - // var expected = new Bgra32(9, 115, 202, 127); - - // // act - // short4.PackFromBgra32(expected); - // short4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromArgb32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedByte4); - // var actual = default(Argb32); - // var expected = new Argb32(9, 115, 202, 127); - - // // act - // short4.PackFromArgb32(expected); - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(NormalizedByte4); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedByte4_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(NormalizedByte4); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index e02d513c2a..83eab82ac8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -69,129 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void NormalizedShort2_PackFromRgba32_ToRgb24() - //{ - // // arrange - // var actual = default(Rgb24); - // var short2 = new NormalizedShort2(); - // var rgba = new Rgba32(141, 90, 0, 0); - // var expected = new Rgb24(141, 90, 0); - - // // act - // short2.PackFromRgba32(rgba); - // short2.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToRgb24() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Rgb24); - // var expected = new Rgb24(141, 90, 0); - - // // act - // short2.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToRgba32() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Rgba32); - // var expected = new Rgba32(141, 90, 0, 255); - - // // act - // short2.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToBgr24() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Bgr24); - // var expected = new Bgr24(141, 90, 0); - - // // act - // short2.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToBgra32() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Bgra32); - // var expected = new Bgra32(141, 90, 0, 255); - - // // act - // short2.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_ToArgb32() - //{ - // // arrange - // var short2 = new NormalizedShort2(0.1f, -0.3f); - // var actual = default(Argb32); - // var expected = new Argb32(141, 90, 0, 255); - - // // act - // short2.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(NormalizedShort2); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort2_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(NormalizedShort2); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 25ffbb348a..40b2d05e31 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // arrange var pixel = default(NormalizedShort4); Vector4 scaled = new NormalizedShort4(Vector4.One).ToScaledVector4(); - ulong expected = (ulong)0x7FFF7FFF7FFF7FFF; + ulong expected = 0x7FFF7FFF7FFF7FFF; // act pixel.PackFromScaledVector4(scaled); @@ -61,145 +61,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - //[Fact] - //public void NormalizedShort4_ToRgb24() - //{ - // // arrange - // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(141, 90, 192); - - // // act - // short4.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_ToRgba32() - //{ - // // arrange - // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(141, 90, 192, 39); - - // // act - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_ToBgr24() - //{ - // // arrange - // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(141, 90, 192); - - // // act - // short4.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_ToArgb32() - //{ - // // arrange - // var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Argb32); - // var expected = new Argb32(141, 90, 192, 39); - - // // act - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedShort4); - // var expected = new Rgba32(9, 115, 202, 127); - // var actual = default(Rgba32); - - // // act - // short4.PackFromRgba32(expected); - // short4.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromBgra32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedShort4); - // var actual = default(Bgra32); - // var expected = new Bgra32(9, 115, 202, 127); - - // // act - // short4.PackFromBgra32(expected); - // short4.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromArgb32_ToRgba32() - //{ - // // arrange - // var short4 = default(NormalizedShort4); - // var actual = default(Argb32); - // var expected = new Argb32(9, 115, 202, 127); - - // // act - // short4.PackFromArgb32(expected); - // short4.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(NormalizedShort4); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void NormalizedShort4_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(NormalizedShort4); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 69ecc553e7..135843e35f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -68,97 +68,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector2.Zero, new Rg32(Vector2.One * -1234.0f).ToVector2()); Assert.Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2()); } - - //[Fact] - //public void Rg32_ToRgb24() - //{ - // // arrange - // var rg32 = new Rg32(0.1f, -0.3f); - // var actual = default(Rgb24); - // var expected = new Rgb24(25, 0, 0); - - // // act - // rg32.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_ToRgba32() - //{ - // // arrange - // var rg32 = new Rg32(0.1f, -0.3f); - // var actual = default(Rgba32); - // var expected = new Rgba32(25, 0, 0, 255); - - // // act - // rg32.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_ToBgr24() - //{ - // // arrange - // var rg32 = new Rg32(0.1f, -0.3f); - // var actual = default(Bgr24); - // var expected = new Bgr24(25, 0, 0); - - // // act - // rg32.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_ToArgb32() - //{ - // // arrange - // var rg32 = new Rg32(0.1f, -0.3f); - // var actual = default(Argb32); - // var expected = new Argb32(25, 0, 0, 255); - - // // act - // rg32.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Rg32); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 65535, 0); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rg32_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Rg32); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 65535, 0, 65535); - - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index fcbef1374f..aa6d9024cd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -1,175 +1,112 @@ -//// Copyright (c) Six Labors and contributors. -//// Licensed under the Apache License, Version 2.0. - -//using System; -//using System.Numerics; -//using SixLabors.ImageSharp.PixelFormats; -//using Xunit; - -//namespace SixLabors.ImageSharp.Tests.PixelFormats -//{ -// public class Rgb24Tests -// { -// public static readonly TheoryData ColorData = -// new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; - -// [Theory] -// [MemberData(nameof(ColorData))] -// public void Constructor(byte r, byte g, byte b) -// { -// var p = new Rgb24(r, g, b); - -// Assert.Equal(r, p.R); -// Assert.Equal(g, p.G); -// Assert.Equal(b, p.B); -// } - -// [Fact] -// public unsafe void ByteLayoutIsSequentialRgb() -// { -// var color = new Rgb24(1, 2, 3); -// byte* ptr = (byte*)&color; - -// Assert.Equal(1, ptr[0]); -// Assert.Equal(2, ptr[1]); -// Assert.Equal(3, ptr[2]); -// } - -// [Theory] -// [MemberData(nameof(ColorData))] -// public void Equals_WhenTrue(byte r, byte g, byte b) -// { -// var x = new Rgb24(r, g, b); -// var y = new Rgb24(r, g, b); - -// Assert.True(x.Equals(y)); -// Assert.True(x.Equals((object)y)); -// Assert.Equal(x.GetHashCode(), y.GetHashCode()); -// } - -// [Theory] -// [InlineData(1, 2, 3, 1, 2, 4)] -// [InlineData(0, 255, 0, 0, 244, 0)] -// [InlineData(1, 255, 0, 0, 255, 0)] -// public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) -// { -// var a = new Rgb24(r1, g1, b1); -// var b = new Rgb24(r2, g2, b2); - -// Assert.False(a.Equals(b)); -// Assert.False(a.Equals((object)b)); -// } - -// [Fact] -// public void PackFromRgba32() -// { -// var rgb = default(Rgb24); -// rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); - -// Assert.Equal(1, rgb.R); -// Assert.Equal(2, rgb.G); -// Assert.Equal(3, rgb.B); -// } - -// private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( -// r / 255f, -// g / 255f, -// b / 255f, -// a / 255f); - -// [Fact] -// public void PackFromVector4() -// { -// var rgb = default(Rgb24); -// rgb.PackFromVector4(Vec(1, 2, 3, 4)); - -// Assert.Equal(1, rgb.R); -// Assert.Equal(2, rgb.G); -// Assert.Equal(3, rgb.B); -// } - -// [Fact] -// public void ToVector4() -// { -// var rgb = new Rgb24(1, 2, 3); - -// Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); -// } - -// [Fact] -// public void ToRgb24() -// { -// var rgb = new Rgb24(1, 2, 3); -// var dest = default(Rgb24); - -// rgb.ToRgb24(ref dest); - -// Assert.Equal(rgb, dest); -// } - -// [Fact] -// public void ToRgba32() -// { -// var rgb = new Rgb24(1, 2, 3); -// var rgba = default(Rgba32); - -// rgb.ToRgba32(ref rgba); - -// Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); -// } - -// [Fact] -// public void ToBgr24() -// { -// var rgb = new Rgb24(1, 2, 3); -// var bgr = default(Bgr24); - -// rgb.ToBgr24(ref bgr); - -// Assert.Equal(new Bgr24(1, 2, 3), bgr); -// } - -// [Fact] -// public void ToBgra32() -// { -// var rgb = new Rgb24(1, 2, 3); -// var bgra = default(Bgra32); - -// rgb.ToBgra32(ref bgra); - -// Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); -// } - -// [Fact] -// public void Rgb24_PackFromRgb48_ToRgb48() -// { -// // arrange -// var input = default(Rgb24); -// var actual = default(Rgb48); -// var expected = new Rgb48(65535, 0, 65535); - -// // act -// input.PackFromRgb48(expected); -// input.ToRgb48(ref actual); - -// // assert -// Assert.Equal(expected, actual); -// } - -// [Fact] -// public void Rgb24_PackFromRgba64_ToRgba64() -// { -// // arrange -// var input = default(Rgb24); -// var actual = default(Rgba64); -// var expected = new Rgba64(65535, 0, 65535, 65535); - -// // act -// input.PackFromRgba64(expected); -// input.ToRgba64(ref actual); - -// // assert -// Assert.Equal(expected, actual); -// } -// } -//} \ No newline at end of file +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Rgb24Tests + { + public static readonly TheoryData ColorData = + new TheoryData() + { + { 1, 2, 3 }, + { 4, 5, 6 }, + { 0, 255, 42 } + }; + + [Theory] + [MemberData(nameof(ColorData))] + public void Constructor(byte r, byte g, byte b) + { + var p = new Rgb24(r, g, b); + + Assert.Equal(r, p.R); + Assert.Equal(g, p.G); + Assert.Equal(b, p.B); + } + + [Fact] + public unsafe void ByteLayoutIsSequentialRgb() + { + var color = new Rgb24(1, 2, 3); + byte* ptr = (byte*)&color; + + Assert.Equal(1, ptr[0]); + Assert.Equal(2, ptr[1]); + Assert.Equal(3, ptr[2]); + } + + [Theory] + [MemberData(nameof(ColorData))] + public void Equals_WhenTrue(byte r, byte g, byte b) + { + var x = new Rgb24(r, g, b); + var y = new Rgb24(r, g, b); + + Assert.True(x.Equals(y)); + Assert.True(x.Equals((object)y)); + Assert.Equal(x.GetHashCode(), y.GetHashCode()); + } + + [Theory] + [InlineData(1, 2, 3, 1, 2, 4)] + [InlineData(0, 255, 0, 0, 244, 0)] + [InlineData(1, 255, 0, 0, 255, 0)] + public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) + { + var a = new Rgb24(r1, g1, b1); + var b = new Rgb24(r2, g2, b2); + + Assert.False(a.Equals(b)); + Assert.False(a.Equals((object)b)); + } + + [Fact] + public void PackFromRgba32() + { + var rgb = default(Rgb24); + rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + + Assert.Equal(1, rgb.R); + Assert.Equal(2, rgb.G); + Assert.Equal(3, rgb.B); + } + + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + r / 255f, + g / 255f, + b / 255f, + a / 255f); + + [Fact] + public void PackFromVector4() + { + var rgb = default(Rgb24); + rgb.PackFromVector4(Vec(1, 2, 3, 4)); + + Assert.Equal(1, rgb.R); + Assert.Equal(2, rgb.G); + Assert.Equal(3, rgb.B); + } + + [Fact] + public void ToVector4() + { + var rgb = new Rgb24(1, 2, 3); + + Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); + } + + [Fact] + public void ToRgba32() + { + var rgb = new Rgb24(1, 2, 3); + var rgba = rgb.ToRgba32(); + + Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 2af488e3cd..16dfd7f577 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -1,192 +1,61 @@ -//// Copyright (c) Six Labors and contributors. -//// Licensed under the Apache License, Version 2.0. - -//using System.Numerics; -//using SixLabors.ImageSharp.PixelFormats; -//using Xunit; - -//namespace SixLabors.ImageSharp.Tests.PixelFormats -//{ -// public class Rgb48Tests -// { -// [Fact] -// public void Rgb48_Values() -// { -// var rgb = new Rgba64(5243, 9830, 19660, 29491); - -// Assert.Equal(5243, rgb.R); -// Assert.Equal(9830, rgb.G); -// Assert.Equal(19660, rgb.B); -// Assert.Equal(29491, rgb.A); -// } - -// [Fact] -// public void Rgb48_ToVector4() -// { -// Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(0, 0, 0, 0).ToVector4()); -// Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); -// } - -// [Fact] -// public void Rgb48_ToScaledVector4() -// { -// // arrange -// var short2 = new Rgb48(Vector3.One); - -// // act -// Vector4 actual = short2.ToScaledVector4(); - -// // assert -// Assert.Equal(1, actual.X); -// Assert.Equal(1, actual.Y); -// Assert.Equal(1, actual.Z); -// Assert.Equal(1, actual.W); -// } - -// [Fact] -// public void Rgb48_PackFromScaledVector4() -// { -// // arrange -// var pixel = default(Rgb48); -// var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); -// var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); - -// // act -// Vector4 scaled = short3.ToScaledVector4(); -// pixel.PackFromScaledVector4(scaled); - -// // assert -// Assert.Equal(expected, pixel); -// } - -// //[Fact] -// //public void Rgb48_Clamping() -// //{ -// // Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.One * -1234.0f).ToVector4()); -// // Assert.Equal(Vector4.One, new Rgb48(Vector3.One * 1234.0f).ToVector4()); -// //} - -// //[Fact] -// //public void Rgb48_ToRgb24() -// //{ -// // // arrange -// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Rgb24); -// // var expected = new Rgb24(20, 38, 76); - -// // // act -// // rgba48.ToRgb24(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_ToRgba32() -// //{ -// // // arrange -// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Rgba32); -// // var expected = new Rgba32(20, 38, 76, 255); - -// // // act -// // rgba48.ToRgba32(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_ToArgb32() -// //{ -// // // arrange -// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Argb32); -// // var expected = new Argb32(20, 38, 76, 255); - -// // // act -// // rgba48.ToArgb32(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgba64_ToBgr24() -// //{ -// // // arrange -// // var rgb48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Bgr24); -// // var expected = new Bgr24(20, 38, 76); - -// // // act -// // rgb48.ToBgr24(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_ToBgra32() -// //{ -// // // arrange -// // var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); -// // var actual = default(Bgra32); -// // var expected = new Bgra32(20, 38, 76, 255); - -// // // act -// // rgba48.ToBgra32(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_PackFromRgba32_ToRgba32() -// //{ -// // // arrange -// // var rgb48 = default(Rgb48); -// // var actual = default(Rgba32); -// // var expected = new Rgba32(20, 38, 76, 255); - -// // // act -// // rgb48.PackFromRgba32(expected); -// // rgb48.ToRgba32(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_PackFromRgb48_ToRgb48() -// //{ -// // // arrange -// // var input = default(Rgb48); -// // var actual = default(Rgb48); -// // var expected = new Rgb48(65535, 0, 65535); - -// // // act -// // input.PackFromRgb48(expected); -// // input.ToRgb48(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} - -// //[Fact] -// //public void Rgb48_PackFromRgba64_ToRgba64() -// //{ -// // // arrange -// // var input = default(Rgb48); -// // var actual = default(Rgba64); -// // var expected = new Rgba64(65535, 0, 65535, 65535); - -// // // act -// // input.PackFromRgba64(expected); -// // input.ToRgba64(ref actual); - -// // // assert -// // Assert.Equal(expected, actual); -// //} -// } -//} +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Rgb48Tests + { + [Fact] + public void Rgb48_Values() + { + var rgb = new Rgba64(5243, 9830, 19660, 29491); + + Assert.Equal(5243, rgb.R); + Assert.Equal(9830, rgb.G); + Assert.Equal(19660, rgb.B); + Assert.Equal(29491, rgb.A); + } + + [Fact] + public void Rgb48_ToVector4() + => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); + + [Fact] + public void Rgb48_ToScaledVector4() + => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); + + [Fact] + public void Rgb48_PackFromScaledVector4() + { + // arrange + var pixel = default(Rgb48); + var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + + // act + Vector4 scaled = short3.ToScaledVector4(); + pixel.PackFromScaledVector4(scaled); + + // assert + Assert.Equal(expected, pixel); + } + + [Fact] + public void Rgb48_ToRgba32() + { + // arrange + var rgba48 = new Rgb48(5140, 9766, 19532); + var expected = new Rgba32(20, 38, 76, 255); + + // act + var actual = rgba48.ToRgba32(); + + // assert + Assert.Equal(expected, actual); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index d8ad6d3f1e..243d4a44c9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -71,144 +71,18 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba1010102(Vector4.One * 1234.0f).ToVector4()); } - //[Fact] - //public void Rgba1010102_ToRgb24() - //{ - // // arrange - // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgb24); - // var expected = new Rgb24(25, 0, 128); - - // // act - // rgba.ToRgb24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_ToRgba32() - //{ - // // arrange - // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Rgba32); - // var expected = new Rgba32(25, 0, 128, 0); - - // // act - // rgba.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_ToBgr24() - //{ - // // arrange - // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgr24); - // var expected = new Bgr24(25, 0, 128); - - // // act - // rgba.ToBgr24(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_ToBgra32() - //{ - // // arrange - // var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - // var actual = default(Bgra32); - // var expected = new Bgra32(25, 0, 128, 0); - - // // act - // rgba.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var rgba = default(Rgba1010102); - // var expected = new Rgba32(25, 0, 128, 0); - // var actual = default(Rgba32); - - // // act - // rgba.PackFromRgba32(expected); - // rgba.ToRgba32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromBgra32_ToBgra32() - //{ - // // arrange - // var rgba = default(Rgba1010102); - // var expected = new Bgra32(25, 0, 128, 0); - // var actual = default(Bgra32); - - // // act - // rgba.PackFromBgra32(expected); - // rgba.ToBgra32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromArgb32_ToArgb32() - //{ - // // arrange - // var rgba = default(Rgba1010102); - // var expected = new Argb32(25, 0, 128, 0); - // var actual = default(Argb32); - - // // act - // rgba.PackFromArgb32(expected); - // rgba.ToArgb32(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromRgb48_ToRgb48() - //{ - // // arrange - // var input = default(Rgba1010102); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - // input.ToRgb48(ref actual); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba1010102_PackFromRgba64_ToRgba64() - //{ - // // arrange - // var input = default(Rgba1010102); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 65535); + [Fact] + public void Rgba1010102_ToRgba32() + { + // arrange + var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); + var expected = new Rgba32(25, 0, 128, 0); - // // act - // input.PackFromRgba64(expected); - // input.ToRgba64(ref actual); + // act + var actual = rgba.ToRgba32(); - // // assert - // Assert.Equal(expected, actual); - //} + // assert + Assert.Equal(expected, actual); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 185fc5635d..e9ac5377d2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -77,70 +77,19 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, one.ToVector4()); } - //[Fact] - //public void Rgba64_ToRgba32() - //{ - // // arrange - // var rgba64 = new Rgba64( - // (ushort)(0.08f * ushort.MaxValue), - // (ushort)(0.15f * ushort.MaxValue), - // (ushort)(0.30f * ushort.MaxValue), - // (ushort)(0.45f * ushort.MaxValue)); - // var actual = default(Rgba32); - // var expected = new Rgba32(20, 38, 76, 115); - - // // act - // actual = rgba64.ToRgba32(); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba64_PackFromRgba32_ToRgba32() - //{ - // // arrange - // var rgba64 = default(Rgba64); - // var actual = default(Rgba32); - // var expected = new Rgba32(20, 38, 76, 115); - - // // act - // rgba64.PackFromRgba32(expected); - // actual = rgba64.ToRgba32(); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgb48_PackFromRgb48() - //{ - // // arrange - // var input = default(Rgba64); - // var actual = default(Rgb48); - // var expected = new Rgb48(65535, 0, 65535); - - // // act - // input.PackFromRgb48(expected); - - // // assert - // Assert.Equal(expected, actual); - //} - - //[Fact] - //public void Rgba64_PackFromRgba64() - //{ - // // arrange - // var input = default(Rgba64); - // var actual = default(Rgba64); - // var expected = new Rgba64(65535, 0, 65535, 0); + [Fact] + public void Rgba64_ToRgba32() + { + // arrange + var rgba64 = new Rgba64(5140, 9766, 19532, 29555); + var actual = default(Rgba32); + var expected = new Rgba32(20, 38, 76, 115); - // // act - // input.PackFromRgba64(expected); - // actual.PackFromScaledVector4(input.ToScaledVector4()); + // act + actual = rgba64.ToRgba32(); - // // assert - // Assert.Equal(expected, actual); - //} + // assert + Assert.Equal(expected, actual); + } } } diff --git a/tests/Images/External b/tests/Images/External index 1a807d17b4..ee90e5f322 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 1a807d17b4cf5ab50558983d4137614cabe96ce3 +Subproject commit ee90e5f32218027744b5d40058b587cc1047b76f From 260a8f8c9a3d0730e836a606e10e5802d5b0fe1e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 14 Oct 2018 22:43:02 +0200 Subject: [PATCH 013/238] BulkConvertByteToNormalizedFloat --- src/ImageSharp/Common/Extensions/SimdUtils.cs | 75 +- .../PixelFormats/Rgba32.PixelOperations.cs | 12 +- .../Color/Bulk/ToVector4.cs | 31 +- .../PixelFormats/PixelOperationsTests.cs | 1384 +++++++++-------- 4 files changed, 802 insertions(+), 700 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs index 7b77fefcac..db1e80dda2 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.cs @@ -7,6 +7,8 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp { /// @@ -103,6 +105,47 @@ namespace SixLabors.ImageSharp } } + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + if (!Vector.IsHardwareAccelerated) + { + throw new InvalidOperationException( + "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); + } + + DebugGuard.IsTrue((dest.Length % Vector.Count) == 0, nameof(source), "dest.Length should be divisable by Vector.Count!"); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dest.Length / 8; + Octet.OfUInt32 temp = default; + + for (int i = 0; i < n; i++) + { + Octet.OfByte sVal = Unsafe.Add(ref sourceBase, i); + + // This call is the bottleneck now: + temp.LoadFrom(ref sVal); + + Vector vi = Unsafe.As>(ref temp); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + Unsafe.Add(ref destBaseAsFloat, i) = vf; + } + } + /// /// Same as but clamps overflown values before conversion. /// @@ -181,6 +224,19 @@ namespace SixLabors.ImageSharp { return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfByte src) + { + this.V0 = src.V0; + this.V1 = src.V1; + this.V2 = src.V2; + this.V3 = src.V3; + this.V4 = src.V4; + this.V5 = src.V5; + this.V6 = src.V6; + this.V7 = src.V7; + } } [StructLayout(LayoutKind.Explicit, Size = 8)] @@ -215,16 +271,17 @@ namespace SixLabors.ImageSharp return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; } - public void LoadFrom(ref OfUInt32 i) + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfUInt32 src) { - this.V0 = (byte)i.V0; - this.V1 = (byte)i.V1; - this.V2 = (byte)i.V2; - this.V3 = (byte)i.V3; - this.V4 = (byte)i.V4; - this.V5 = (byte)i.V5; - this.V6 = (byte)i.V6; - this.V7 = (byte)i.V7; + this.V0 = (byte)src.V0; + this.V1 = (byte)src.V1; + this.V2 = (byte)src.V2; + this.V3 = (byte)src.V3; + this.V4 = (byte)src.V4; + this.V5 = (byte)src.V5; + this.V6 = (byte)src.V6; + this.V7 = (byte)src.V7; } } } diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 2629ce3f79..76e119ba44 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -57,14 +57,14 @@ namespace SixLabors.ImageSharp.PixelFormats int unpackedRawCount = count * 4; ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); - ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); - ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); + ref WideRgba destBaseAsWide = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); + ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsWide); + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWide); for (int i = 0; i < count; i++) { uint sVal = Unsafe.Add(ref sourceBase, i); - ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i); + ref WideRgba dst = ref Unsafe.Add(ref destBaseAsWide, i); // This call is the bottleneck now: dst.Load(sVal); @@ -174,10 +174,10 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Value type to store -s unpacked into multiple -s. + /// Value type to store -s widened into multiple -s. /// [StructLayout(LayoutKind.Sequential)] - private struct UnpackedRGBA + private struct WideRgba { private uint r; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 50fac25139..7b6f902d82 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -6,8 +6,13 @@ using System.Buffers; using System; using System.Numerics; +using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Environments; +using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -17,11 +22,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public abstract class ToVector4 where TPixel : struct, IPixel { - private IMemoryOwner source; + protected IMemoryOwner source; - private IMemoryOwner destination; + protected IMemoryOwner destination; - [Params(64, 300, 1024)] + [Params( + //64, + 1024)] public int Count { get; set; } [GlobalSetup] @@ -38,7 +45,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark(Baseline = true)] + [Benchmark] public void PerElement() { Span s = this.source.GetSpan(); @@ -51,7 +58,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + [Benchmark(Baseline = true)] public void CommonBulk() { new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); @@ -64,7 +71,21 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } + [CoreJob] + //[ClrJob] public class ToVector4_Rgba32 : ToVector4 { + class Config : ManualConfig + { + } + + [Benchmark] + public void BulkConvertByteToNormalizedFloat() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 9e41fd94f3..a96da03e7f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -1,93 +1,117 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; -using Xunit.Abstractions; - -namespace SixLabors.ImageSharp.Tests.PixelFormats -{ - public partial class PixelOperationsTests - { - public class Rgba32 : PixelOperationsTests - { - public Rgba32(ITestOutputHelper output) - : base(output) - { - } - - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - [Fact] - public void IsSpecialImplementation() - { - Assert.IsType(PixelOperations.Instance); - } - - [Fact] - public void ToVector4SimdAligned() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) - ); - } - - - // [Fact] // Profiling benchmark - enable manually! -#pragma warning disable xUnit1013 // Public method should be marked as test - public void Benchmark_ToVector4() -#pragma warning restore xUnit1013 // Public method should be marked as test - { - int times = 200000; - int count = 1024; - - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) - using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) - { - this.Measure( - times, - () => - { - PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); - }); - } - } - } - - public class Argb32 : PixelOperationsTests - { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public Argb32(ITestOutputHelper output) - : base(output) - { - } - - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - } - - [Theory] - [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider dummy) - where TPixel : struct, IPixel - { - Assert.NotNull(PixelOperations.Instance); +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public partial class PixelOperationsTests + { + public class Rgba32 : PixelOperationsTests + { + public Rgba32(ITestOutputHelper output) + : base(output) + { + } + + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() + { + Assert.IsType(PixelOperations.Instance); + } + + [Fact] + public void ToVector4SimdAligned() + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) + ); + } + + [Fact] + public void BulkConvertByteToNormalizedFloat() + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => + { + ReadOnlySpan sBytes = MemoryMarshal.Cast(s); + Span dFloats = MemoryMarshal.Cast(d.Memory.Span); + + SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + ); + } + + + // [Fact] // Profiling benchmark - enable manually! +#pragma warning disable xUnit1013 // Public method should be marked as test + public void Benchmark_ToVector4() +#pragma warning restore xUnit1013 // Public method should be marked as test + { + int times = 200000; + int count = 1024; + + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) + { + this.Measure( + times, + () => + { + PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); + }); + } + } + } + + public class Argb32 : PixelOperationsTests + { + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public Argb32(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + } + + [Theory] + [WithBlankImages(1, 1, PixelTypes.All)] + public void GetGlobalInstance(TestImageProvider dummy) + where TPixel : struct, IPixel + { + Assert.NotNull(PixelOperations.Instance); } [Fact] @@ -99,594 +123,594 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Transparent)); Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal,PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - } - } - - public abstract class PixelOperationsTests : MeasureFixture - where TPixel : struct, IPixel - { - protected PixelOperationsTests(ITestOutputHelper output) - : base(output) - { - } - - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - private static PixelOperations Operations => PixelOperations.Instance; - - internal static TPixel[] CreateExpectedPixelData(Vector4[] source) - { - var expected = new TPixel[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i].PackFromVector4(source[i]); - } - return expected; - } - - internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source) - { - var expected = new TPixel[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i].PackFromScaledVector4(source[i]); - } - return expected; - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromVector4(int count) - { - Vector4[] source = CreateVector4TestData(count); - TPixel[] expected = CreateExpectedPixelData(source); - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromScaledVector4(int count) - { - Vector4[] source = CreateVector4TestData(count); - TPixel[] expected = CreateScaledExpectedPixelData(source); - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) - ); - } - - internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToVector4(); - } - return expected; - } - - internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToScaledVector4(); - } - return expected; - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToVector4(int count) - { - TPixel[] source = CreatePixelTestData(count); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => Operations.ToVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToScaledVector4(int count) - { - TPixel[] source = CreateScaledPixelTestData(count); - Vector4[] expected = CreateExpectedScaledVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) - { - byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - - expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgb24Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - source[i].ToRgb24(ref rgb); - expected[i3] = rgb.R; - expected[i3 + 1] = rgb.G; - expected[i3 + 2] = rgb.B; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgba32Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToRgba32(ref rgba); - expected[i4] = rgba.R; - expected[i4 + 1] = rgba.G; - expected[i4 + 2] = rgba.B; - expected[i4 + 3] = rgba.A; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) - { - byte[] source = CreateByteTestData(count * 6); - Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; - - var rgba64 = new Rgba64(0, 0, 0, 65535); - for (int i = 0; i < count; i++) - { - int i6 = i * 6; - rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; - expected[i].PackFromRgba64(rgba64); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgb48Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; - - for (int i = 0; i < count; i++) - { - int i6 = i * 6; - source[i].ToRgb48(ref rgb); - Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); - expected[i6] = rgb48Bytes[0]; - expected[i6 + 1] = rgb48Bytes[1]; - expected[i6 + 2] = rgb48Bytes[2]; - expected[i6 + 3] = rgb48Bytes[3]; - expected[i6 + 4] = rgb48Bytes[4]; - expected[i6 + 5] = rgb48Bytes[5]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) - { - byte[] source = CreateByteTestData(count * 8); - Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToRgba64Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; - - for (int i = 0; i < count; i++) - { - int i8 = i * 8; - source[i].ToRgba64(ref rgba); - Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); - expected[i8] = rgba64Bytes[0]; - expected[i8 + 1] = rgba64Bytes[1]; - expected[i8 + 2] = rgba64Bytes[2]; - expected[i8 + 3] = rgba64Bytes[3]; - expected[i8 + 4] = rgba64Bytes[4]; - expected[i8 + 5] = rgba64Bytes[5]; - expected[i8 + 6] = rgba64Bytes[6]; - expected[i8 + 7] = rgba64Bytes[7]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) - { - byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - - expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToBgr24Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); - - for (int i = 0; i < count; i++) - { - int i3 = i * 3; - source[i].ToBgr24(ref bgr); - expected[i3] = bgr.B; - expected[i3 + 1] = bgr.G; - expected[i3 + 2] = bgr.R; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToZyxwBytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToBgra32(ref bgra); - expected[i4] = bgra.B; - expected[i4 + 1] = bgra.G; - expected[i4 + 2] = bgra.R; - expected[i4 + 3] = bgra.A; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) - { - byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToArgb32Bytes(int count) - { - TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var argb = default(Argb32); - - for (int i = 0; i < count; i++) - { - int i4 = i * 4; - source[i].ToArgb32(ref argb); - expected[i4] = argb.A; - expected[i4 + 1] = argb.R; - expected[i4 + 2] = argb.G; - expected[i4 + 3] = argb.B; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) - ); - } - - private class TestBuffers : IDisposable - where TSource : struct - where TDest : struct - { - public TSource[] SourceBuffer { get; } - public IMemoryOwner ActualDestBuffer { get; } - public TDest[] ExpectedDestBuffer { get; } - - public TestBuffers(TSource[] source, TDest[] expectedDest) - { - this.SourceBuffer = source; - this.ExpectedDestBuffer = expectedDest; - this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); - } - - public void Dispose() - { - this.ActualDestBuffer.Dispose(); - } - - private const float Tolerance = 0.0001f; - - public void Verify() - { - int count = this.ExpectedDestBuffer.Length; - - if (typeof(TDest) == typeof(Vector4)) - { - - Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); - Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - - for (int i = 0; i < count; i++) - { - // ReSharper disable PossibleNullReferenceException - Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); - // ReSharper restore PossibleNullReferenceException - } - } - else - { - Span expected = this.ExpectedDestBuffer.AsSpan(); - Span actual = this.ActualDestBuffer.GetSpan(); - for (int i = 0; i < count; i++) - { - Assert.Equal(expected[i], actual[i]); - } - } - } - } - - internal static void TestOperation( - TSource[] source, - TDest[] expected, - Action> action) - where TSource : struct - where TDest : struct - { - using (var buffers = new TestBuffers(source, expected)) - { - action(buffers.SourceBuffer, buffers.ActualDestBuffer); - buffers.Verify(); - } - } - - internal static Vector4[] CreateVector4TestData(int length) - { - var result = new Vector4[length]; - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - result[i] = GetVector(rnd); - } - return result; - } - - internal static TPixel[] CreatePixelTestData(int length) - { - var result = new TPixel[length]; - - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - Vector4 v = GetVector(rnd); - result[i].PackFromVector4(v); - } - - return result; - } - - internal static TPixel[] CreateScaledPixelTestData(int length) - { - var result = new TPixel[length]; - - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - Vector4 v = GetVector(rnd); - result[i].PackFromScaledVector4(v); - } - - return result; - } - - internal static byte[] CreateByteTestData(int length) - { - byte[] result = new byte[length]; - var rnd = new Random(42); // Deterministic random values - - for (int i = 0; i < result.Length; i++) - { - result[i] = (byte)rnd.Next(255); - } - return result; - } - - internal static Vector4 GetVector(Random rnd) - { - return new Vector4( - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble() - ); - } - - [StructLayout(LayoutKind.Sequential)] - private unsafe struct Rgba64Bytes - { - public fixed byte Data[8]; - - public byte this[int idx] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ref byte self = ref Unsafe.As(ref this); - return Unsafe.Add(ref self, idx); - } - } - } - } + } + } + + public abstract class PixelOperationsTests : MeasureFixture + where TPixel : struct, IPixel + { + protected PixelOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + private static PixelOperations Operations => PixelOperations.Instance; + + internal static TPixel[] CreateExpectedPixelData(Vector4[] source) + { + var expected = new TPixel[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i].PackFromVector4(source[i]); + } + return expected; + } + + internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source) + { + var expected = new TPixel[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i].PackFromScaledVector4(source[i]); + } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromVector4(int count) + { + Vector4[] source = CreateVector4TestData(count); + TPixel[] expected = CreateExpectedPixelData(source); + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromScaledVector4(int count) + { + Vector4[] source = CreateVector4TestData(count); + TPixel[] expected = CreateScaledExpectedPixelData(source); + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) + ); + } + + internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToVector4(); + } + return expected; + } + + internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToScaledVector4(); + } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToVector4(int count) + { + TPixel[] source = CreatePixelTestData(count); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => Operations.ToVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToScaledVector4(int count) + { + TPixel[] source = CreateScaledPixelTestData(count); + Vector4[] expected = CreateExpectedScaledVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgb24Bytes(int count) + { + byte[] source = CreateByteTestData(count * 3); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgb24Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + var rgb = default(Rgb24); + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + source[i].ToRgb24(ref rgb); + expected[i3] = rgb.R; + expected[i3 + 1] = rgb.G; + expected[i3 + 2] = rgb.B; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgba32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgba32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var rgba = default(Rgba32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + source[i].ToRgba32(ref rgba); + expected[i4] = rgba.R; + expected[i4 + 1] = rgba.G; + expected[i4 + 2] = rgba.B; + expected[i4 + 3] = rgba.A; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgb48Bytes(int count) + { + byte[] source = CreateByteTestData(count * 6); + Span sourceSpan = source.AsSpan(); + var expected = new TPixel[count]; + + var rgba64 = new Rgba64(0, 0, 0, 65535); + for (int i = 0; i < count; i++) + { + int i6 = i * 6; + rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; + expected[i].PackFromRgba64(rgba64); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgb48Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 6]; + Rgb48 rgb = default; + + for (int i = 0; i < count; i++) + { + int i6 = i * 6; + source[i].ToRgb48(ref rgb); + Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); + expected[i6] = rgb48Bytes[0]; + expected[i6 + 1] = rgb48Bytes[1]; + expected[i6 + 2] = rgb48Bytes[2]; + expected[i6 + 3] = rgb48Bytes[3]; + expected[i6 + 4] = rgb48Bytes[4]; + expected[i6 + 5] = rgb48Bytes[5]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromRgba64Bytes(int count) + { + byte[] source = CreateByteTestData(count * 8); + Span sourceSpan = source.AsSpan(); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i8 = i * 8; + expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToRgba64Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 8]; + Rgba64 rgba = default; + + for (int i = 0; i < count; i++) + { + int i8 = i * 8; + source[i].ToRgba64(ref rgba); + Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); + expected[i8] = rgba64Bytes[0]; + expected[i8 + 1] = rgba64Bytes[1]; + expected[i8 + 2] = rgba64Bytes[2]; + expected[i8 + 3] = rgba64Bytes[3]; + expected[i8 + 4] = rgba64Bytes[4]; + expected[i8 + 5] = rgba64Bytes[5]; + expected[i8 + 6] = rgba64Bytes[6]; + expected[i8 + 7] = rgba64Bytes[7]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromBgr24Bytes(int count) + { + byte[] source = CreateByteTestData(count * 3); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToBgr24Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + var bgr = default(Bgr24); + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + source[i].ToBgr24(ref bgr); + expected[i3] = bgr.B; + expected[i3 + 1] = bgr.G; + expected[i3 + 2] = bgr.R; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromBgra32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToZyxwBytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var bgra = default(Bgra32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + source[i].ToBgra32(ref bgra); + expected[i4] = bgra.B; + expected[i4 + 1] = bgra.G; + expected[i4 + 2] = bgra.R; + expected[i4 + 3] = bgra.A; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromArgb32Bytes(int count) + { + byte[] source = CreateByteTestData(count * 4); + var expected = new TPixel[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToArgb32Bytes(int count) + { + TPixel[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + var argb = default(Argb32); + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + source[i].ToArgb32(ref argb); + expected[i4] = argb.A; + expected[i4 + 1] = argb.R; + expected[i4 + 2] = argb.G; + expected[i4 + 3] = argb.B; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + ); + } + + private class TestBuffers : IDisposable + where TSource : struct + where TDest : struct + { + public TSource[] SourceBuffer { get; } + public IMemoryOwner ActualDestBuffer { get; } + public TDest[] ExpectedDestBuffer { get; } + + public TestBuffers(TSource[] source, TDest[] expectedDest) + { + this.SourceBuffer = source; + this.ExpectedDestBuffer = expectedDest; + this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); + } + + public void Dispose() + { + this.ActualDestBuffer.Dispose(); + } + + private const float Tolerance = 0.0001f; + + public void Verify() + { + int count = this.ExpectedDestBuffer.Length; + + if (typeof(TDest) == typeof(Vector4)) + { + + Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); + Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); + + for (int i = 0; i < count; i++) + { + // ReSharper disable PossibleNullReferenceException + Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); + // ReSharper restore PossibleNullReferenceException + } + } + else + { + Span expected = this.ExpectedDestBuffer.AsSpan(); + Span actual = this.ActualDestBuffer.GetSpan(); + for (int i = 0; i < count; i++) + { + Assert.Equal(expected[i], actual[i]); + } + } + } + } + + internal static void TestOperation( + TSource[] source, + TDest[] expected, + Action> action) + where TSource : struct + where TDest : struct + { + using (var buffers = new TestBuffers(source, expected)) + { + action(buffers.SourceBuffer, buffers.ActualDestBuffer); + buffers.Verify(); + } + } + + internal static Vector4[] CreateVector4TestData(int length) + { + var result = new Vector4[length]; + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + result[i] = GetVector(rnd); + } + return result; + } + + internal static TPixel[] CreatePixelTestData(int length) + { + var result = new TPixel[length]; + + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromVector4(v); + } + + return result; + } + + internal static TPixel[] CreateScaledPixelTestData(int length) + { + var result = new TPixel[length]; + + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromScaledVector4(v); + } + + return result; + } + + internal static byte[] CreateByteTestData(int length) + { + byte[] result = new byte[length]; + var rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + result[i] = (byte)rnd.Next(255); + } + return result; + } + + internal static Vector4 GetVector(Random rnd) + { + return new Vector4( + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble() + ); + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct Rgba64Bytes + { + public fixed byte Data[8]; + + public byte this[int idx] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ref byte self = ref Unsafe.As(ref this); + return Unsafe.Add(ref self, idx); + } + } + } + } } \ No newline at end of file From af7d96d21462e6e080488f7d1933d1430834fadd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 15 Oct 2018 01:11:59 +0200 Subject: [PATCH 014/238] SIMD byte -> float conversion: BulkConvertByteToNormalizedFloatFast --- src/ImageSharp/Common/Extensions/SimdUtils.cs | 45 +++++++++++++++++-- .../Color/Bulk/ToVector4.cs | 16 +++++-- .../ImageSharp.Benchmarks.csproj | 2 +- .../PixelFormats/PixelOperationsTests.cs | 24 ++++++++++ .../Tests/TestEnvironmentTests.cs | 2 + 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs index db1e80dda2..56118a7644 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.cs @@ -105,13 +105,50 @@ namespace SixLabors.ImageSharp } } - internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + /// + /// Fast -> conversion for RyuJIT runtimes having dotnet/coreclr#10662 merged. + /// + /// https://github.com/dotnet/coreclr/pull/10662 + /// + /// + internal static void BulkConvertByteToNormalizedFloatFast(ReadOnlySpan source, Span dest) { - if (!Vector.IsHardwareAccelerated) + Guard.IsTrue( + source.Length % Vector.Count == 0, + nameof(source), + "dest.Length should be divisable by Vector.Count!"); + + int n = source.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) { - throw new InvalidOperationException( - "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = Vector.ConvertToSingle(w0) * scale; + Vector f1 = Vector.ConvertToSingle(w1) * scale; + Vector f2 = Vector.ConvertToSingle(w2) * scale; + Vector f3 = Vector.ConvertToSingle(w3) * scale; + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; } + } + + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); DebugGuard.IsTrue((dest.Length % Vector.Count) == 0, nameof(source), "dest.Length should be divisable by Vector.Count!"); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 7b6f902d82..0e5e9d94f4 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, - 1024)] + 2048)] public int Count { get; set; } [GlobalSetup] @@ -72,14 +72,14 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [CoreJob] - //[ClrJob] + [ClrJob] public class ToVector4_Rgba32 : ToVector4 { class Config : ManualConfig { } - [Benchmark] + //[Benchmark] public void BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -87,5 +87,15 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } + + [Benchmark] + public void BulkConvertByteToNormalizedFloatFast() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats); + } + } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 36b7d4db4b..e470e78212 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,6 +1,6 @@  - netcoreapp2.0;net461 + netcoreapp2.1;net461 Exe True SixLabors.ImageSharp.Benchmarks diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index a96da03e7f..2e84886c03 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -73,6 +73,30 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ); } + [Fact] + public void BulkConvertByteToNormalizedFloatFast() + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(128); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => + { + ReadOnlySpan sBytes = MemoryMarshal.Cast(s); + Span dFloats = MemoryMarshal.Cast(d.Memory.Span); + + SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats); + } + ); + } + // [Fact] // Profiling benchmark - enable manually! #pragma warning disable xUnit1013 // Public method should be marked as test diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 8a3e69059f..30bb16c2a0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -3,6 +3,8 @@ using System; using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats; From 281c52786aff178f33ae5a928d4caff7b614a9ca Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 15 Oct 2018 01:30:35 +0200 Subject: [PATCH 015/238] move tests --- src/ImageSharp/Common/Extensions/SimdUtils.cs | 2 +- .../Color/Bulk/ToVector4.cs | 2 +- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 40 ++++++++++++++++ .../PixelFormats/PixelOperationsTests.cs | 48 ------------------- .../TestUtilities/TestDataGenerator.cs | 7 +++ 5 files changed, 49 insertions(+), 50 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs index 56118a7644..481e0726df 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp /// https://github.com/dotnet/coreclr/pull/10662 /// /// - internal static void BulkConvertByteToNormalizedFloatFast(ReadOnlySpan source, Span dest) + internal static void BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(ReadOnlySpan source, Span dest) { Guard.IsTrue( source.Length % Vector.Count == 0, diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 0e5e9d94f4..3ea256e85a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats); + SimdUtils.BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(sBytes, dFloats); } } diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index c6c3b68f33..4e39af70fd 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -186,6 +186,46 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, dest); } + [Theory] + [InlineData(1, 0)] + [InlineData(2, 32)] + [InlineData(3, 128)] + public void BulkConvertByteToNormalizedFloat(int seed, int count) + { + if (this.SkipOnNonAvx2()) + { + return; + } + + byte[] source = new Random(seed).GenerateRandomByteArray(count); + float[] result = new float[count]; + float[] expected = source.Select(b => (float)b / 255f).ToArray(); + + SimdUtils.BulkConvertByteToNormalizedFloat(source, result); + + Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); + } + + [Theory] + [InlineData(1, 0)] + [InlineData(2, 32)] + [InlineData(3, 128)] + public void BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(int seed, int count) + { + if (!Vector.IsHardwareAccelerated) + { + return; + } + + byte[] source = new Random(seed).GenerateRandomByteArray(count); + float[] result = new float[count]; + float[] expected = source.Select(b => (float)b / 255f).ToArray(); + + SimdUtils.BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(source, result); + + Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); + } + [Theory] [InlineData(0)] [InlineData(7)] diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 2e84886c03..4d7ec71e72 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -49,54 +49,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ); } - [Fact] - public void BulkConvertByteToNormalizedFloat() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => - { - ReadOnlySpan sBytes = MemoryMarshal.Cast(s); - Span dFloats = MemoryMarshal.Cast(d.Memory.Span); - - SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - ); - } - - [Fact] - public void BulkConvertByteToNormalizedFloatFast() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(128); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => - { - ReadOnlySpan sBytes = MemoryMarshal.Cast(s); - Span dFloats = MemoryMarshal.Cast(d.Memory.Span); - - SimdUtils.BulkConvertByteToNormalizedFloatFast(sBytes, dFloats); - } - ); - } - // [Fact] // Profiling benchmark - enable manually! #pragma warning disable xUnit1013 // Public method should be marked as test diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 0b1b89cc00..6f3b18e1fc 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -46,6 +46,13 @@ namespace SixLabors.ImageSharp.Tests return values; } + public static byte[] GenerateRandomByteArray(this Random rnd, int length) + { + byte[] values = new byte[length]; + rnd.NextBytes(values); + return values; + } + private static float GetRandomFloat(Random rnd, float minVal, float maxVal) { return (float)rnd.NextDouble() * (maxVal - minVal) + minVal; From 1c2aee03a633e89a017ba70120248264234174ff Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Oct 2018 18:16:13 +0100 Subject: [PATCH 016/238] Generate bulk pixel operations for all standard packing operations and fix conversion --- src/ImageSharp/ImageFrame{TPixel}.cs | 14 +- src/ImageSharp/ImageSharp.csproj | 72 ++ src/ImageSharp/PixelFormats/Alpha8.cs | 8 + src/ImageSharp/PixelFormats/Argb32.cs | 31 +- src/ImageSharp/PixelFormats/Bgr24.cs | 17 +- src/ImageSharp/PixelFormats/Bgr565.cs | 8 + src/ImageSharp/PixelFormats/Bgra32.cs | 33 +- src/ImageSharp/PixelFormats/Bgra4444.cs | 8 + src/ImageSharp/PixelFormats/Bgra5551.cs | 11 +- src/ImageSharp/PixelFormats/Byte4.cs | 12 +- .../Argb32.PixelOperations.Generated.cs | 177 +++++ .../Argb32.PixelOperations.Generated.tt | 85 +++ .../Bgr24.PixelOperations.Generated.cs | 177 +++++ .../Bgr24.PixelOperations.Generated.tt | 85 +++ .../Bgra32.PixelOperations.Generated.cs | 177 +++++ .../Bgra32.PixelOperations.Generated.tt | 85 +++ .../Gray16.PixelOperations.Generated.cs | 177 +++++ .../Gray16.PixelOperations.Generated.tt | 85 +++ .../Gray8.PixelOperations.Generated.cs | 177 +++++ .../Gray8.PixelOperations.Generated.tt | 85 +++ .../PixelOperations{TPixel}.Generated.cs | 468 ++++++------ .../PixelOperations{TPixel}.Generated.tt | 70 +- .../Rgb24.PixelOperations.Generated.cs | 177 +++++ .../Rgb24.PixelOperations.Generated.tt | 85 +++ .../Rgb48.PixelOperations.Generated.cs | 177 +++++ .../Rgb48.PixelOperations.Generated.tt | 85 +++ .../Rgba32.PixelOperations.Generated.cs | 120 +-- .../Rgba32.PixelOperations.Generated.tt | 70 +- .../Rgba64.PixelOperations.Generated.cs | 177 +++++ .../Rgba64.PixelOperations.Generated.tt | 85 +++ src/ImageSharp/PixelFormats/Gray16.cs | 44 +- src/ImageSharp/PixelFormats/Gray8.cs | 34 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 27 +- src/ImageSharp/PixelFormats/HalfVector2.cs | 8 + src/ImageSharp/PixelFormats/HalfVector4.cs | 8 + src/ImageSharp/PixelFormats/IPixel.cs | 12 + .../PixelFormats/NormalizedByte2.cs | 8 + .../PixelFormats/NormalizedByte4.cs | 8 + .../PixelFormats/NormalizedShort2.cs | 8 + .../PixelFormats/NormalizedShort4.cs | 8 + .../PixelFormats/PixelOperations{TPixel}.cs | 54 ++ src/ImageSharp/PixelFormats/Rg32.cs | 8 + src/ImageSharp/PixelFormats/Rgb24.cs | 19 +- src/ImageSharp/PixelFormats/Rgb48.cs | 22 +- src/ImageSharp/PixelFormats/Rgba1010102.cs | 14 +- .../PixelFormats/Rgba32.PixelOperations.cs | 66 +- src/ImageSharp/PixelFormats/Rgba32.cs | 16 + src/ImageSharp/PixelFormats/Rgba64.cs | 24 +- .../PixelFormats/RgbaVector.Definitions.cs | 721 ------------------ .../RgbaVector.PixelOperations.cs | 18 +- src/ImageSharp/PixelFormats/RgbaVector.cs | 10 +- src/ImageSharp/PixelFormats/Short2.cs | 12 +- src/ImageSharp/PixelFormats/Short4.cs | 12 +- .../PixelFormats/PixelOperationsTests.cs | 644 +++++++++++----- 54 files changed, 3441 insertions(+), 1402 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs create mode 100644 src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt delete mode 100644 src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index be1792ced1..ecf9e13ceb 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; -using System.Numerics; using System.Runtime.CompilerServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; @@ -289,22 +287,16 @@ namespace SixLabors.ImageSharp var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.DeepClone()); - ParallelHelper.IterateRowsWithTempBuffer( + ParallelHelper.IterateRows( this.Bounds(), configuration, - (rows, tempRowBuffer) => + (rows) => { for (int y = rows.Min; y < rows.Max; y++) { Span sourceRow = this.GetPixelRowSpan(y); Span targetRow = target.GetPixelRowSpan(y); - Span tempRowSpan = tempRowBuffer.Span; - - PixelOperations.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length); - PixelOperations.Instance.PackFromScaledVector4( - tempRowSpan, - targetRow, - targetRow.Length); + PixelOperations.Instance.To(sourceRow, targetRow, sourceRow.Length); } }); diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index a7ca0a014c..7eec03cb6a 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -76,10 +76,42 @@ TextTemplatingFileGenerator PixelOperations{TPixel}.Generated.cs + + TextTemplatingFileGenerator + Argb32.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Bgr24.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Bgra32.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Gray8.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Gray16.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Rgb24.PixelOperations.Generated.cs + TextTemplatingFileGenerator Rgba32.PixelOperations.Generated.cs + + TextTemplatingFileGenerator + Rgb48.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Rgba64.PixelOperations.Generated.cs + PorterDuffFunctions.Generated.cs TextTemplatingFileGenerator @@ -110,11 +142,51 @@ True PixelOperations{TPixel}.Generated.tt + + True + True + Argb32.PixelOperations.Generated.tt + + + True + True + Bgr24.PixelOperations.Generated.tt + + + True + True + Bgra32.PixelOperations.Generated.tt + + + True + True + Gray8.PixelOperations.Generated.tt + + + True + True + Gray16.PixelOperations.Generated.tt + + + True + True + Rgb24.PixelOperations.Generated.tt + True True Rgba32.PixelOperations.Generated.tt + + True + True + Rgb48.PixelOperations.Generated.tt + + + True + True + Rgba64.PixelOperations.Generated.tt + True True diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 063200c69e..1e724768d0 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -79,6 +79,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A; @@ -91,6 +95,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 0da8516a3e..1e3bd93262 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// as it avoids the need to create new values for modification operations. /// [StructLayout(LayoutKind.Sequential)] - public struct Argb32 : IPixel, IPackedVector + public partial struct Argb32 : IPixel, IPackedVector { /// /// Gets or sets the alpha component. @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -187,6 +187,16 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -218,6 +228,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = byte.MaxValue; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) @@ -269,13 +289,6 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.Argb.GetHashCode(); - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(InliningOptions.ShortMethod)] - internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); - /// /// Packs the four floats into a color. /// diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index 063fed5221..ed65bebf7f 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Explicit)] - public struct Bgr24 : IPixel + public partial struct Bgr24 : IPixel { /// /// The blue component. @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -104,6 +104,10 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.B; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this = source; + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -132,6 +136,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = rgb; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this = source.Bgr; diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 5b19fb25c1..454f458b12 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -87,6 +87,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToVector4()); @@ -99,6 +103,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromVector4(source.ToVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 6fd0867797..9b0ed4f96d 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Bgra32 : IPixel, IPackedVector + public partial struct Bgra32 : IPixel, IPackedVector { /// /// Gets or sets the blue component. @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -151,7 +151,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.PackedValue; + public void PackFromBgr24(Bgr24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -184,6 +194,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); @@ -220,13 +240,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public override string ToString() => $"Bgra32({this.B}, {this.G}, {this.R}, {this.A})"; - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(InliningOptions.ShortMethod)] - internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); - /// /// Packs a into a color. /// diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 8a5e3f76b3..08484eba8d 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -90,6 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -102,6 +106,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 25f289b846..df0a467301 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -91,6 +91,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -103,6 +107,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -147,8 +155,5 @@ namespace SixLabors.ImageSharp.PixelFormats | (((int)Math.Round(vector.Z * 31F) & 0x1F) << 0) | (((int)Math.Round(vector.W) & 0x1) << 15)); } - - [MethodImpl(InliningOptions.ShortMethod)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index fbdf4862db..34546e0271 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -89,11 +89,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToByteScaledVector4()); + public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToByteScaledVector4()); + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -103,6 +107,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs new file mode 100644 index 0000000000..0b40df8dae --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Argb32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt new file mode 100644 index 0000000000..f35adee022 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromArgb32(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Argb32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs new file mode 100644 index 0000000000..e895254576 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgr24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt new file mode 100644 index 0000000000..76163549b0 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgr24(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgr24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs new file mode 100644 index 0000000000..2311e0bde6 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgra32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt new file mode 100644 index 0000000000..4c2925d18f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromBgra32(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgra32 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs new file mode 100644 index 0000000000..a2d9aa755f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray16 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt new file mode 100644 index 0000000000..b900e343a7 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray16(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray16 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs new file mode 100644 index 0000000000..de2c11d4d9 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray8 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt new file mode 100644 index 0000000000..4590420e57 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromGray8(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray8 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index 852ff73e0e..66966543fc 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -11,633 +11,633 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba64(temp); + ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromArgb32(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba64Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToArgb32(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgb48(temp); + ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromBgr24(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb48Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToBgr24(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); + ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromBgra32(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToBgra32(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Gray8 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromBgra32(temp); + ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromGray8(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgra32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToGray8(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Gray16 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp.Rgb = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); + ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromGray16(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToGray16(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp.Bgr = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); + ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgb24(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgr24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgb24(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromArgb32(temp); + ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgba32(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToArgb32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToArgb32(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgba32(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Gray8 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromGray8(temp); + ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgb48(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray8Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray8(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgb48(sourcePixels, MemoryMarshal.Cast(destBytes), count); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts 'count' elements in 'source` span of data to a span of -s. /// - /// The source of data. + /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref Gray16 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; + ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromGray16(temp); + ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFromRgba64(sp); } } /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); } + /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span dest, int count) + internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(dest); + ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray16Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray16(sourceColors, MemoryMarshal.Cast(destBytes), count); + this.ToRgba64(sourcePixels, MemoryMarshal.Cast(destBytes), count); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index 9fbe57ed9b..913dabb087 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -11,7 +11,7 @@ <#@ output extension=".cs" #> <# - void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) + void GeneratePackFromMethods(string pixelType) { #> @@ -25,17 +25,15 @@ { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors<<#=tempPixelType#>>.Black; + ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=assignToTempCode#> - dp.PackFrom<#=tempPixelType#>(temp); + ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.PackFrom<#=pixelType#>(sp); } } @@ -51,6 +49,7 @@ { this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); } + <# } @@ -61,19 +60,20 @@ /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. /// /// The span of source pixels - /// The destination span of data. + /// The destination span of data. /// The number of pixels to convert. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) + internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(dest); + ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); } } @@ -82,13 +82,13 @@ /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// - /// The to the source colors. + /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void To<#=pixelType#>Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) + internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast>(destBytes), count); + this.To<#=pixelType#>(sourcePixels, MemoryMarshal.Cast>(destBytes), count); } <# } @@ -107,32 +107,32 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations {<# - GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgba64"); - - GeneratePackFromMethods("Rgb48", "Rgb48", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgb48"); - - GeneratePackFromMethods("Rgba32", "Rgba32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgba32"); - - GeneratePackFromMethods("Bgra32", "Bgra32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Bgra32"); - - GeneratePackFromMethods("Rgb24", "Rgba32", "temp.Rgb = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgb24"); + GeneratePackFromMethods("Argb32"); + GenerateToDestFormatMethods("Argb32"); - GeneratePackFromMethods("Bgr24", "Rgba32", "temp.Bgr = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Bgr24"); GenerateToDestFormatMethods("Bgr24"); - GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Argb32"); + GeneratePackFromMethods("Bgra32"); + GenerateToDestFormatMethods("Bgra32"); - GeneratePackFromMethods("Gray8", "Gray8", "temp = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Gray8"); GenerateToDestFormatMethods("Gray8"); - GeneratePackFromMethods("Gray16", "Gray16", "temp = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Gray16"); GenerateToDestFormatMethods("Gray16"); + GeneratePackFromMethods("Rgb24"); + GenerateToDestFormatMethods("Rgb24"); + + GeneratePackFromMethods("Rgba32"); + GenerateToDestFormatMethods("Rgba32"); + + GeneratePackFromMethods("Rgb48"); + GenerateToDestFormatMethods("Rgb48"); + + GeneratePackFromMethods("Rgba64"); + GenerateToDestFormatMethods("Rgba64"); + #> } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs new file mode 100644 index 0000000000..ad4ee2764e --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt new file mode 100644 index 0000000000..6a10b401f4 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb24(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb24 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs new file mode 100644 index 0000000000..0a1ef03873 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb48 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt new file mode 100644 index 0000000000..e38c85bf62 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgb48(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb48 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgba64"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs index 9621505952..bd3e014b4d 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs @@ -13,133 +13,161 @@ namespace SixLabors.ImageSharp.PixelFormats /// public partial struct Rgba32 { + + /// + /// Provides optimized overrides for bulk operations. + /// internal partial class PixelOperations { + /// + internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + /// - internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - Unsafe.As(ref dp) = sp; dp.A = byte.MaxValue; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(dest); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp = Unsafe.As(ref sp); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.Bgr = sp; dp.A = byte.MaxValue; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(dest); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.Bgr; + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(dest); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromRgba32(sp); } } /// - internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A; + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba32(sp); } } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span dest, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(dest); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromRgba32(sp); } } diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt index 9d9145f0b9..23d0be740e 100644 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt @@ -9,45 +9,24 @@ <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> <# - void GeneratePackFromMethod(string pixelType, string converterCode) + void GenerateConvertToMethod(string pixelType) { #> /// - internal override void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - <#=converterCode#> - } - } - <# - } - - void GenerateConvertToMethod(string pixelType, string converterCode) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(dest); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < count; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - <#=converterCode#> + + dp.PackFromRgba32(sp); } } <# @@ -68,20 +47,37 @@ namespace SixLabors.ImageSharp.PixelFormats /// public partial struct Rgba32 { + + /// + /// Provides optimized overrides for bulk operations. + /// internal partial class PixelOperations { - <# - GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = byte.MaxValue;"); - GenerateConvertToMethod("Rgb24", "dp = Unsafe.As(ref sp);"); + /// + internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = byte.MaxValue;"); - GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;"); - - GeneratePackFromMethod("Bgra32", "dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A;"); - GenerateConvertToMethod("Bgra32", "dp.PackFromRgba32(sp);"); + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - GeneratePackFromMethod("Argb32", "dp.R = sp.R; dp.G = sp.G; dp.B = sp.B; dp.A = sp.A;"); - GenerateConvertToMethod("Argb32", "dp.PackFromRgba32(sp);"); + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgb48"); + GenerateConvertToMethod("Rgba64"); #> } diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs new file mode 100644 index 0000000000..e6f9b37a70 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba64 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + /// + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt new file mode 100644 index 0000000000..e998341570 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt @@ -0,0 +1,85 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +<# + void GenerateConvertToMethod(string pixelType) + { + #> + + /// + internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.PackFromRgba64(sp); + } + } + <# + } +#> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// +namespace SixLabors.ImageSharp.PixelFormats +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba64 + { + + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <# + GenerateConvertToMethod("Argb32"); + GenerateConvertToMethod("Bgr24"); + GenerateConvertToMethod("Bgra32"); + GenerateConvertToMethod("Gray8"); + GenerateConvertToMethod("Gray16"); + GenerateConvertToMethod("Rgb24"); + GenerateConvertToMethod("Rgba32"); + GenerateConvertToMethod("Rgb48"); + #> + + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index f9aada9374..34f221d79c 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -13,9 +13,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// - public struct Gray16 : IPixel, IPackedVector + public partial struct Gray16 : IPixel, IPackedVector { private const float Max = ushort.MaxValue; + private const float Average = 1 / 3F; /// /// Initializes a new instance of the struct. @@ -49,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Gray16 left, Gray16 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -63,11 +64,8 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.PackedValue = ImageMaths.Get16BitBT709Luminance( - (ushort)MathF.Round(vector.X), - (ushort)MathF.Round(vector.Y), - (ushort)MathF.Round(vector.Z)); + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max * Average; + this.PackedValue = (ushort)MathF.Round(vector.X + vector.Y + vector.Z); } /// @@ -88,6 +86,16 @@ namespace SixLabors.ImageSharp.PixelFormats ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -106,6 +114,16 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackedValue = source.PackedValue; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) @@ -130,7 +148,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + public void PackFromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); /// public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other); @@ -145,5 +163,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + internal void ConvertFromRgbaScaledVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + (ushort)MathF.Round(vector.X), + (ushort)MathF.Round(vector.Y), + (ushort)MathF.Round(vector.Z)); + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index b1fa2b1e14..5812405876 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -12,17 +12,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// - public struct Gray8 : IPixel, IPackedVector + public partial struct Gray8 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// private static readonly Vector4 MaxBytes = new Vector4(255F); - - /// - /// The half vector value. - /// private static readonly Vector4 Half = new Vector4(0.5F); + private const float Average = 1 / 3F; /// /// Initializes a new instance of the struct. @@ -56,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Gray8 left, Gray8 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -72,9 +66,8 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - - this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes) * Average; + this.PackedValue = (byte)(vector.X + vector.Y + vector.Z); } /// @@ -89,6 +82,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); @@ -101,6 +98,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); @@ -138,5 +139,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + internal void ConvertFromRgbaScaledVector4(Vector4 vector) + { + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 8048a3825d..78edc9a08e 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -14,16 +14,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// public struct HalfSingle : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - /// /// Initializes a new instance of the struct. /// @@ -89,6 +79,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -101,6 +95,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -137,14 +135,5 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.PackedValue.GetHashCode(); - - [MethodImpl(InliningOptions.ShortMethod)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - return Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index f398f508ba..e3777bc2fb 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -90,6 +90,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -102,6 +106,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 45d93efc09..079c3ee383 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -98,6 +98,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -110,6 +114,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index a3017501ce..87125fa0a3 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -61,6 +61,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromArgb32(Argb32 source); + /// + /// Packs the pixel from an value. + /// + /// The value. + void PackFromBgr24(Bgr24 source); + /// /// Packs the pixel from an value. /// @@ -79,6 +85,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromGray16(Gray16 source); + /// + /// Packs the pixel from an value. + /// + /// The value. + void PackFromRgb24(Rgb24 source); + /// /// Packs the pixel from an value. /// diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 86b5280902..3eaa69c03e 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -97,6 +97,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -113,6 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index b538e4a449..e0e3e65020 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -102,6 +102,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -114,6 +118,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 6135826f48..0aa5736379 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -97,6 +97,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -109,6 +113,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 9717829a24..577e901544 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -104,6 +104,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -116,6 +120,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index b12a2bfa58..f1b40e81f0 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -105,6 +105,60 @@ namespace SixLabors.ImageSharp.PixelFormats } } + /// + /// Performs a bulk conversion of a collection of one pixel format into another. + /// + /// The pixel format. + /// The to the source colors. + /// The to the destination colors. + /// The number of pixels to convert. + internal virtual void To(ReadOnlySpan sourceColors, Span destinationColors, int count) + where TPixel2 : struct, IPixel + { + GuardSpans(sourceColors, nameof(sourceColors), destinationColors, nameof(destinationColors), count); + + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); + + // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the + // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm. + // One of the requirements of PackFromScaledVector4/ToScaledVector4 is that it unaware of this and + // packs/unpacks the pixel without and conversion so we employ custom methods do do this. + if (typeof(TPixel2).Equals(typeof(Gray16))) + { + ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref gray16Ref, i); + dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); + } + + return; + } + + if (typeof(TPixel2).Equals(typeof(Gray8))) + { + ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref gray8Ref, i); + dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); + } + + return; + } + + // Normal converson + ref TPixel2 destRef = ref MemoryMarshal.GetReference(destinationColors); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel2 dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromScaledVector4(sp.ToScaledVector4()); + } + } + /// /// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size. /// Throwing an if the condition is not met. diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index 3375a9753b..02c294b4ff 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -85,6 +85,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -97,6 +101,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index ae037b3764..a2b896605d 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Explicit)] - public struct Rgb24 : IPixel + public partial struct Rgb24 : IPixel { /// /// The red component. @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -118,6 +118,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.B; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -148,7 +157,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this = Unsafe.As(ref source); + public void PackFromRgb24(Rgb24 source) => this = source; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgba32(Rgba32 source) => this = source.Rgb; /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 2ee1be6fe4..7406fda429 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Rgb48 : IPixel + public partial struct Rgb48 : IPixel { private const float Max = ushort.MaxValue; @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -104,6 +104,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -136,6 +145,15 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = source.PackedValue; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 8bcf34f309..86b639e229 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -91,6 +91,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -105,16 +109,20 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - /// + /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 40d8e0190d..3111a6ee15 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -86,33 +86,10 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - - if (count < 256 || !Vector.IsHardwareAccelerated) - { - // Doesn't worth to bother with SIMD: - base.ToVector4(sourceColors, destinationVectors, count); - return; - } - - int remainder = count % Vector.Count; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount); - } + internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) => this.PackFromVector4(sourceVectors, destinationColors, count); - if (remainder > 0) - { - sourceColors = sourceColors.Slice(alignedCount); - destinationVectors = destinationVectors.Slice(alignedCount); - base.ToVector4(sourceColors, destinationVectors, remainder); - } - } + /// + internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) => this.ToVector4(sourceColors, destinationVectors, count); /// internal override void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) @@ -145,25 +122,32 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) => this.ToVector4(sourceColors, destinationVectors, count); - - /// - internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) => this.PackFromVector4(sourceVectors, destinationColors, count); - - /// - internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); + Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - source.Slice(0, count).CopyTo(destPixels); - } + if (count < 256 || !Vector.IsHardwareAccelerated) + { + // Doesn't worth to bother with SIMD: + base.ToVector4(sourceColors, destinationVectors, count); + return; + } - /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); + int remainder = count % Vector.Count; + int alignedCount = count - remainder; - sourcePixels.Slice(0, count).CopyTo(dest); + if (alignedCount > 0) + { + ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount); + } + + if (remainder > 0) + { + sourceColors = sourceColors.Slice(alignedCount); + destinationVectors = destinationVectors.Slice(alignedCount); + base.ToVector4(sourceColors, destinationVectors, remainder); + } } /// diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 83620c823c..e7814d23ac 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -246,6 +246,14 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.Bgr = source; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -277,6 +285,14 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = byte.MaxValue; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.Rgb = source; + this.A = byte.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this = source; diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 623f7051af..738c5e3dd8 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Rgba64 : IPixel, IPackedVector + public partial struct Rgba64 : IPixel, IPackedVector { private const float Max = ushort.MaxValue; @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -134,6 +134,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ushort.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) @@ -165,6 +175,16 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = ushort.MaxValue; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ushort.MaxValue; + } + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) diff --git a/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs b/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs deleted file mode 100644 index 2ef37c43ae..0000000000 --- a/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs +++ /dev/null @@ -1,721 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Provides operators and composition algorithms. - /// - public partial struct RgbaVector - { - /// - /// Represents a matching the W3C definition that has an hex value of #F0F8FF. - /// - public static readonly RgbaVector AliceBlue = NamedColors.AliceBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAEBD7. - /// - public static readonly RgbaVector AntiqueWhite = NamedColors.AntiqueWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FFFF. - /// - public static readonly RgbaVector Aqua = NamedColors.Aqua; - - /// - /// Represents a matching the W3C definition that has an hex value of #7FFFD4. - /// - public static readonly RgbaVector Aquamarine = NamedColors.Aquamarine; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0FFFF. - /// - public static readonly RgbaVector Azure = NamedColors.Azure; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5F5DC. - /// - public static readonly RgbaVector Beige = NamedColors.Beige; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4C4. - /// - public static readonly RgbaVector Bisque = NamedColors.Bisque; - - /// - /// Represents a matching the W3C definition that has an hex value of #000000. - /// - public static readonly RgbaVector Black = NamedColors.Black; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFEBCD. - /// - public static readonly RgbaVector BlanchedAlmond = NamedColors.BlanchedAlmond; - - /// - /// Represents a matching the W3C definition that has an hex value of #0000FF. - /// - public static readonly RgbaVector Blue = NamedColors.Blue; - - /// - /// Represents a matching the W3C definition that has an hex value of #8A2BE2. - /// - public static readonly RgbaVector BlueViolet = NamedColors.BlueViolet; - - /// - /// Represents a matching the W3C definition that has an hex value of #A52A2A. - /// - public static readonly RgbaVector Brown = NamedColors.Brown; - - /// - /// Represents a matching the W3C definition that has an hex value of #DEB887. - /// - public static readonly RgbaVector BurlyWood = NamedColors.BurlyWood; - - /// - /// Represents a matching the W3C definition that has an hex value of #5F9EA0. - /// - public static readonly RgbaVector CadetBlue = NamedColors.CadetBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #7FFF00. - /// - public static readonly RgbaVector Chartreuse = NamedColors.Chartreuse; - - /// - /// Represents a matching the W3C definition that has an hex value of #D2691E. - /// - public static readonly RgbaVector Chocolate = NamedColors.Chocolate; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF7F50. - /// - public static readonly RgbaVector Coral = NamedColors.Coral; - - /// - /// Represents a matching the W3C definition that has an hex value of #6495ED. - /// - public static readonly RgbaVector CornflowerBlue = NamedColors.CornflowerBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF8DC. - /// - public static readonly RgbaVector Cornsilk = NamedColors.Cornsilk; - - /// - /// Represents a matching the W3C definition that has an hex value of #DC143C. - /// - public static readonly RgbaVector Crimson = NamedColors.Crimson; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FFFF. - /// - public static readonly RgbaVector Cyan = NamedColors.Cyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #00008B. - /// - public static readonly RgbaVector DarkBlue = NamedColors.DarkBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #008B8B. - /// - public static readonly RgbaVector DarkCyan = NamedColors.DarkCyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #B8860B. - /// - public static readonly RgbaVector DarkGoldenrod = NamedColors.DarkGoldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #A9A9A9. - /// - public static readonly RgbaVector DarkGray = NamedColors.DarkGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #006400. - /// - public static readonly RgbaVector DarkGreen = NamedColors.DarkGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #BDB76B. - /// - public static readonly RgbaVector DarkKhaki = NamedColors.DarkKhaki; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B008B. - /// - public static readonly RgbaVector DarkMagenta = NamedColors.DarkMagenta; - - /// - /// Represents a matching the W3C definition that has an hex value of #556B2F. - /// - public static readonly RgbaVector DarkOliveGreen = NamedColors.DarkOliveGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF8C00. - /// - public static readonly RgbaVector DarkOrange = NamedColors.DarkOrange; - - /// - /// Represents a matching the W3C definition that has an hex value of #9932CC. - /// - public static readonly RgbaVector DarkOrchid = NamedColors.DarkOrchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B0000. - /// - public static readonly RgbaVector DarkRed = NamedColors.DarkRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #E9967A. - /// - public static readonly RgbaVector DarkSalmon = NamedColors.DarkSalmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #8FBC8B. - /// - public static readonly RgbaVector DarkSeaGreen = NamedColors.DarkSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #483D8B. - /// - public static readonly RgbaVector DarkSlateBlue = NamedColors.DarkSlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #2F4F4F. - /// - public static readonly RgbaVector DarkSlateGray = NamedColors.DarkSlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #00CED1. - /// - public static readonly RgbaVector DarkTurquoise = NamedColors.DarkTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #9400D3. - /// - public static readonly RgbaVector DarkViolet = NamedColors.DarkViolet; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF1493. - /// - public static readonly RgbaVector DeepPink = NamedColors.DeepPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #00BFFF. - /// - public static readonly RgbaVector DeepSkyBlue = NamedColors.DeepSkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #696969. - /// - public static readonly RgbaVector DimGray = NamedColors.DimGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #1E90FF. - /// - public static readonly RgbaVector DodgerBlue = NamedColors.DodgerBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #B22222. - /// - public static readonly RgbaVector Firebrick = NamedColors.Firebrick; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFAF0. - /// - public static readonly RgbaVector FloralWhite = NamedColors.FloralWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #228B22. - /// - public static readonly RgbaVector ForestGreen = NamedColors.ForestGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF00FF. - /// - public static readonly RgbaVector Fuchsia = NamedColors.Fuchsia; - - /// - /// Represents a matching the W3C definition that has an hex value of #DCDCDC. - /// - public static readonly RgbaVector Gainsboro = NamedColors.Gainsboro; - - /// - /// Represents a matching the W3C definition that has an hex value of #F8F8FF. - /// - public static readonly RgbaVector GhostWhite = NamedColors.GhostWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFD700. - /// - public static readonly RgbaVector Gold = NamedColors.Gold; - - /// - /// Represents a matching the W3C definition that has an hex value of #DAA520. - /// - public static readonly RgbaVector Goldenrod = NamedColors.Goldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #808080. - /// - public static readonly RgbaVector Gray = NamedColors.Gray; - - /// - /// Represents a matching the W3C definition that has an hex value of #008000. - /// - public static readonly RgbaVector Green = NamedColors.Green; - - /// - /// Represents a matching the W3C definition that has an hex value of #ADFF2F. - /// - public static readonly RgbaVector GreenYellow = NamedColors.GreenYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0FFF0. - /// - public static readonly RgbaVector Honeydew = NamedColors.Honeydew; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF69B4. - /// - public static readonly RgbaVector HotPink = NamedColors.HotPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #CD5C5C. - /// - public static readonly RgbaVector IndianRed = NamedColors.IndianRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #4B0082. - /// - public static readonly RgbaVector Indigo = NamedColors.Indigo; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFF0. - /// - public static readonly RgbaVector Ivory = NamedColors.Ivory; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0E68C. - /// - public static readonly RgbaVector Khaki = NamedColors.Khaki; - - /// - /// Represents a matching the W3C definition that has an hex value of #E6E6FA. - /// - public static readonly RgbaVector Lavender = NamedColors.Lavender; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF0F5. - /// - public static readonly RgbaVector LavenderBlush = NamedColors.LavenderBlush; - - /// - /// Represents a matching the W3C definition that has an hex value of #7CFC00. - /// - public static readonly RgbaVector LawnGreen = NamedColors.LawnGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFACD. - /// - public static readonly RgbaVector LemonChiffon = NamedColors.LemonChiffon; - - /// - /// Represents a matching the W3C definition that has an hex value of #ADD8E6. - /// - public static readonly RgbaVector LightBlue = NamedColors.LightBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #F08080. - /// - public static readonly RgbaVector LightCoral = NamedColors.LightCoral; - - /// - /// Represents a matching the W3C definition that has an hex value of #E0FFFF. - /// - public static readonly RgbaVector LightCyan = NamedColors.LightCyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAFAD2. - /// - public static readonly RgbaVector LightGoldenrodYellow = NamedColors.LightGoldenrodYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #D3D3D3. - /// - public static readonly RgbaVector LightGray = NamedColors.LightGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #90EE90. - /// - public static readonly RgbaVector LightGreen = NamedColors.LightGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFB6C1. - /// - public static readonly RgbaVector LightPink = NamedColors.LightPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFA07A. - /// - public static readonly RgbaVector LightSalmon = NamedColors.LightSalmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #20B2AA. - /// - public static readonly RgbaVector LightSeaGreen = NamedColors.LightSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #87CEFA. - /// - public static readonly RgbaVector LightSkyBlue = NamedColors.LightSkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #778899. - /// - public static readonly RgbaVector LightSlateGray = NamedColors.LightSlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #B0C4DE. - /// - public static readonly RgbaVector LightSteelBlue = NamedColors.LightSteelBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFE0. - /// - public static readonly RgbaVector LightYellow = NamedColors.LightYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FF00. - /// - public static readonly RgbaVector Lime = NamedColors.Lime; - - /// - /// Represents a matching the W3C definition that has an hex value of #32CD32. - /// - public static readonly RgbaVector LimeGreen = NamedColors.LimeGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAF0E6. - /// - public static readonly RgbaVector Linen = NamedColors.Linen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF00FF. - /// - public static readonly RgbaVector Magenta = NamedColors.Magenta; - - /// - /// Represents a matching the W3C definition that has an hex value of #800000. - /// - public static readonly RgbaVector Maroon = NamedColors.Maroon; - - /// - /// Represents a matching the W3C definition that has an hex value of #66CDAA. - /// - public static readonly RgbaVector MediumAquamarine = NamedColors.MediumAquamarine; - - /// - /// Represents a matching the W3C definition that has an hex value of #0000CD. - /// - public static readonly RgbaVector MediumBlue = NamedColors.MediumBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #BA55D3. - /// - public static readonly RgbaVector MediumOrchid = NamedColors.MediumOrchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #9370DB. - /// - public static readonly RgbaVector MediumPurple = NamedColors.MediumPurple; - - /// - /// Represents a matching the W3C definition that has an hex value of #3CB371. - /// - public static readonly RgbaVector MediumSeaGreen = NamedColors.MediumSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #7B68EE. - /// - public static readonly RgbaVector MediumSlateBlue = NamedColors.MediumSlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FA9A. - /// - public static readonly RgbaVector MediumSpringGreen = NamedColors.MediumSpringGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #48D1CC. - /// - public static readonly RgbaVector MediumTurquoise = NamedColors.MediumTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #C71585. - /// - public static readonly RgbaVector MediumVioletRed = NamedColors.MediumVioletRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #191970. - /// - public static readonly RgbaVector MidnightBlue = NamedColors.MidnightBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5FFFA. - /// - public static readonly RgbaVector MintCream = NamedColors.MintCream; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4E1. - /// - public static readonly RgbaVector MistyRose = NamedColors.MistyRose; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4B5. - /// - public static readonly RgbaVector Moccasin = NamedColors.Moccasin; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFDEAD. - /// - public static readonly RgbaVector NavajoWhite = NamedColors.NavajoWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #000080. - /// - public static readonly RgbaVector Navy = NamedColors.Navy; - - /// - /// Represents a matching the W3C definition that has an hex value of #FDF5E6. - /// - public static readonly RgbaVector OldLace = NamedColors.OldLace; - - /// - /// Represents a matching the W3C definition that has an hex value of #808000. - /// - public static readonly RgbaVector Olive = NamedColors.Olive; - - /// - /// Represents a matching the W3C definition that has an hex value of #6B8E23. - /// - public static readonly RgbaVector OliveDrab = NamedColors.OliveDrab; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFA500. - /// - public static readonly RgbaVector Orange = NamedColors.Orange; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF4500. - /// - public static readonly RgbaVector OrangeRed = NamedColors.OrangeRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #DA70D6. - /// - public static readonly RgbaVector Orchid = NamedColors.Orchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #EEE8AA. - /// - public static readonly RgbaVector PaleGoldenrod = NamedColors.PaleGoldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #98FB98. - /// - public static readonly RgbaVector PaleGreen = NamedColors.PaleGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #AFEEEE. - /// - public static readonly RgbaVector PaleTurquoise = NamedColors.PaleTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #DB7093. - /// - public static readonly RgbaVector PaleVioletRed = NamedColors.PaleVioletRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFEFD5. - /// - public static readonly RgbaVector PapayaWhip = NamedColors.PapayaWhip; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFDAB9. - /// - public static readonly RgbaVector PeachPuff = NamedColors.PeachPuff; - - /// - /// Represents a matching the W3C definition that has an hex value of #CD853F. - /// - public static readonly RgbaVector Peru = NamedColors.Peru; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFC0CB. - /// - public static readonly RgbaVector Pink = NamedColors.Pink; - - /// - /// Represents a matching the W3C definition that has an hex value of #DDA0DD. - /// - public static readonly RgbaVector Plum = NamedColors.Plum; - - /// - /// Represents a matching the W3C definition that has an hex value of #B0E0E6. - /// - public static readonly RgbaVector PowderBlue = NamedColors.PowderBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #800080. - /// - public static readonly RgbaVector Purple = NamedColors.Purple; - - /// - /// Represents a matching the W3C definition that has an hex value of #663399. - /// - public static readonly RgbaVector RebeccaPurple = NamedColors.RebeccaPurple; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF0000. - /// - public static readonly RgbaVector Red = NamedColors.Red; - - /// - /// Represents a matching the W3C definition that has an hex value of #BC8F8F. - /// - public static readonly RgbaVector RosyBrown = NamedColors.RosyBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #4169E1. - /// - public static readonly RgbaVector RoyalBlue = NamedColors.RoyalBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B4513. - /// - public static readonly RgbaVector SaddleBrown = NamedColors.SaddleBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #FA8072. - /// - public static readonly RgbaVector Salmon = NamedColors.Salmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #F4A460. - /// - public static readonly RgbaVector SandyBrown = NamedColors.SandyBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #2E8B57. - /// - public static readonly RgbaVector SeaGreen = NamedColors.SeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF5EE. - /// - public static readonly RgbaVector SeaShell = NamedColors.SeaShell; - - /// - /// Represents a matching the W3C definition that has an hex value of #A0522D. - /// - public static readonly RgbaVector Sienna = NamedColors.Sienna; - - /// - /// Represents a matching the W3C definition that has an hex value of #C0C0C0. - /// - public static readonly RgbaVector Silver = NamedColors.Silver; - - /// - /// Represents a matching the W3C definition that has an hex value of #87CEEB. - /// - public static readonly RgbaVector SkyBlue = NamedColors.SkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #6A5ACD. - /// - public static readonly RgbaVector SlateBlue = NamedColors.SlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #708090. - /// - public static readonly RgbaVector SlateGray = NamedColors.SlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFAFA. - /// - public static readonly RgbaVector Snow = NamedColors.Snow; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FF7F. - /// - public static readonly RgbaVector SpringGreen = NamedColors.SpringGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #4682B4. - /// - public static readonly RgbaVector SteelBlue = NamedColors.SteelBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #D2B48C. - /// - public static readonly RgbaVector Tan = NamedColors.Tan; - - /// - /// Represents a matching the W3C definition that has an hex value of #008080. - /// - public static readonly RgbaVector Teal = NamedColors.Teal; - - /// - /// Represents a matching the W3C definition that has an hex value of #D8BFD8. - /// - public static readonly RgbaVector Thistle = NamedColors.Thistle; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF6347. - /// - public static readonly RgbaVector Tomato = NamedColors.Tomato; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFFF. - /// - public static readonly RgbaVector Transparent = NamedColors.Transparent; - - /// - /// Represents a matching the W3C definition that has an hex value of #40E0D0. - /// - public static readonly RgbaVector Turquoise = NamedColors.Turquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #EE82EE. - /// - public static readonly RgbaVector Violet = NamedColors.Violet; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5DEB3. - /// - public static readonly RgbaVector Wheat = NamedColors.Wheat; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFFF. - /// - public static readonly RgbaVector White = NamedColors.White; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5F5F5. - /// - public static readonly RgbaVector WhiteSmoke = NamedColors.WhiteSmoke; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFF00. - /// - public static readonly RgbaVector Yellow = NamedColors.Yellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #9ACD32. - /// - public static readonly RgbaVector YellowGreen = NamedColors.YellowGreen; - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs index ce40665cd4..aae6ee6940 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs @@ -18,11 +18,23 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override unsafe void ToVector4(ReadOnlySpan sourceColors, Span destVectors, int count) + internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count); + GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - MemoryMarshal.Cast(sourceColors).Slice(0, count).CopyTo(destVectors); + MemoryMarshal.Cast(sourceVectors).Slice(0, count).CopyTo(destinationColors); + } + + /// + internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + => this.ToVector4(sourceColors, destinationVectors, count); + + /// + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + { + GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + + MemoryMarshal.Cast(sourceColors).Slice(0, count).CopyTo(destinationVectors); } } } diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index 5ca0ce406f..b5ccf8aedc 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static RgbaVector FromHex(string hex) => ColorBuilder.FromHex(hex); /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -125,6 +125,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); @@ -137,6 +141,10 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 24430a5d9f..db29b401ed 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -105,11 +105,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -119,10 +119,18 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 4925137470..6d6e5f0845 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -110,11 +110,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -124,10 +124,18 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + /// [MethodImpl(InliningOptions.ShortMethod)] public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 92b04f587e..e9cc98884a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -13,20 +13,257 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.PixelFormats { - public partial class PixelOperationsTests + public class PixelOperationsTests { - public class Rgba32 : PixelOperationsTests + public class Argb32OperationsTests : PixelOperationsTests { - public Rgba32(ITestOutputHelper output) + public Argb32OperationsTests(ITestOutputHelper output) : base(output) { } - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + // For 4.6 test runner MemberData does not work without redeclaring the public field in the + // derived test class: + // TODO: Can this not be delared in the parent class? public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Bgr24OperationsTests : PixelOperationsTests + { + public Bgr24OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Bgra32OperationsTests : PixelOperationsTests + { + public Bgra32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Gray8OperationsTests : PixelOperationsTests + { + public Gray8OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + expected[i].PackFromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) + ); + } + } + + public class Gray16OperationsTests : PixelOperationsTests + { + public Gray16OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + expected[i].PackFromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) + ); + } + } + + public class Rgba32OperationsTests : PixelOperationsTests + { + public Rgba32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); [Fact] public void ToVector4SimdAligned() @@ -36,63 +273,86 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats return; } - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); + Rgba32[] source = CreatePixelTestData(64); Vector4[] expected = CreateExpectedVector4Data(source); TestOperation( source, expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) + (s, d) => Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) ); } - // [Fact] // Profiling benchmark - enable manually! #pragma warning disable xUnit1013 // Public method should be marked as test public void Benchmark_ToVector4() #pragma warning restore xUnit1013 // Public method should be marked as test { - int times = 200000; - int count = 1024; + const int times = 200000; + const int count = 1024; - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) { this.Measure( times, - () => - { - PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); - }); + () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count)); } } } - public class Argb32 : PixelOperationsTests + public class Rgb48OperationsTests : PixelOperationsTests { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public Argb32(ITestOutputHelper output) + public Rgb48OperationsTests(ITestOutputHelper output) : base(output) { } public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class Rgba64OperationsTests : PixelOperationsTests + { + public Rgba64OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + + public class RgbaVectorOperationsTests : PixelOperationsTests + { + public RgbaVectorOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } [Theory] [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider dummy) + public void GetGlobalInstance(TestImageProvider _) where TPixel : struct, IPixel => Assert.NotNull(PixelOperations.Instance); [Fact] public void IsOpaqueColor() { - Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - - Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Transparent)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); + Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); } } @@ -106,7 +366,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - private static PixelOperations Operations => PixelOperations.Instance; + internal static PixelOperations Operations => PixelOperations.Instance; internal static TPixel[] CreateExpectedPixelData(Vector4[] source) { @@ -210,383 +470,333 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) + public void PackFromArgb32Bytes(int count) { - byte[] source = CreateByteTestData(count * 3); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i3 = i * 3; + int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); + expected[i].PackFromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgb24Bytes(int count) + public void ToArgb32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); + byte[] expected = new byte[count * 4]; + var argb = default(Argb32); for (int i = 0; i < count; i++) { - int i3 = i * 3; - rgb.PackFromScaledVector4(source[i].ToScaledVector4()); - expected[i3] = rgb.R; - expected[i3 + 1] = rgb.G; - expected[i3 + 2] = rgb.B; + int i4 = i * 4; + argb.PackFromScaledVector4(source[i].ToScaledVector4()); + + expected[i4] = argb.A; + expected[i4 + 1] = argb.R; + expected[i4 + 2] = argb.G; + expected[i4 + 3] = argb.B; } TestOperation( source, expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) + public void PackFromBgr24Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; + int i3 = i * 3; - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + expected[i].PackFromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgba32Bytes(int count) + public void ToBgr24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); + byte[] expected = new byte[count * 3]; + var bgr = default(Bgr24); for (int i = 0; i < count; i++) { - int i4 = i * 4; - rgba.PackFromScaledVector4(source[i].ToScaledVector4()); - expected[i4] = rgba.R; - expected[i4 + 1] = rgba.G; - expected[i4 + 2] = rgba.B; - expected[i4 + 3] = rgba.A; + int i3 = i * 3; + bgr.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = bgr.B; + expected[i3 + 1] = bgr.G; + expected[i3 + 2] = bgr.R; } TestOperation( source, expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) + public void PackFromBgra32Bytes(int count) { - byte[] source = CreateByteTestData(count * 6); - Span sourceSpan = source.AsSpan(); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; - var rgba64 = new Rgba64(0, 0, 0, 65535); for (int i = 0; i < count; i++) { - int i6 = i * 6; - rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; - expected[i].PackFromRgba64(rgba64); + int i4 = i * 4; + + expected[i].PackFromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgb48Bytes(int count) + public void ToBgra32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; + byte[] expected = new byte[count * 4]; + var bgra = default(Bgra32); for (int i = 0; i < count; i++) { - int i6 = i * 6; - rgb.PackFromScaledVector4(source[i].ToScaledVector4()); - Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); - expected[i6] = rgb48Bytes[0]; - expected[i6 + 1] = rgb48Bytes[1]; - expected[i6 + 2] = rgb48Bytes[2]; - expected[i6 + 3] = rgb48Bytes[3]; - expected[i6 + 4] = rgb48Bytes[4]; - expected[i6 + 5] = rgb48Bytes[5]; + int i4 = i * 4; + bgra.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = bgra.B; + expected[i4 + 1] = bgra.G; + expected[i4 + 2] = bgra.R; + expected[i4 + 3] = bgra.A; } TestOperation( source, expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) + public void PackFromRgb24Bytes(int count) { - byte[] source = CreateByteTestData(count * 8); - Span sourceSpan = source.AsSpan(); + byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + int i3 = i * 3; + + expected[i].PackFromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgba64Bytes(int count) + public void ToRgb24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; + byte[] expected = new byte[count * 3]; + var rgb = default(Rgb24); for (int i = 0; i < count; i++) { - int i8 = i * 8; - rgba.PackFromScaledVector4(source[i].ToScaledVector4()); - Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); - expected[i8] = rgba64Bytes[0]; - expected[i8 + 1] = rgba64Bytes[1]; - expected[i8 + 2] = rgba64Bytes[2]; - expected[i8 + 3] = rgba64Bytes[3]; - expected[i8 + 4] = rgba64Bytes[4]; - expected[i8 + 5] = rgba64Bytes[5]; - expected[i8 + 6] = rgba64Bytes[6]; - expected[i8 + 7] = rgba64Bytes[7]; + int i3 = i * 3; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = rgb.R; + expected[i3 + 1] = rgb.G; + expected[i3 + 2] = rgb.B; } TestOperation( source, expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) + public void PackFromRgba32Bytes(int count) { - byte[] source = CreateByteTestData(count * 3); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i3 = i * 3; + int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); + expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToBgr24Bytes(int count) + public void ToRgba32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); + byte[] expected = new byte[count * 4]; + var rgba = default(Rgba32); for (int i = 0; i < count; i++) { - int i3 = i * 3; - bgr.PackFromScaledVector4(source[i].ToScaledVector4()); - expected[i3] = bgr.B; - expected[i3 + 1] = bgr.G; - expected[i3 + 2] = bgr.R; + int i4 = i * 4; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = rgba.R; + expected[i4 + 1] = rgba.G; + expected[i4 + 2] = rgba.B; + expected[i4 + 3] = rgba.A; } TestOperation( source, expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) + public void PackFromRgb48Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 6); + Span sourceSpan = source.AsSpan(); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + int i6 = i * 6; + expected[i].PackFromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); } TestOperation( source, expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToBgra32Bytes(int count) + public void ToRgb48Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); + byte[] expected = new byte[count * 6]; + Rgb48 rgb = default; for (int i = 0; i < count; i++) { - int i4 = i * 4; - bgra.PackFromScaledVector4(source[i].ToScaledVector4()); - expected[i4] = bgra.B; - expected[i4 + 1] = bgra.G; - expected[i4 + 2] = bgra.R; - expected[i4 + 3] = bgra.A; + int i6 = i * 6; + rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes rgb48Bytes = Unsafe.As(ref rgb); + expected[i6] = rgb48Bytes[0]; + expected[i6 + 1] = rgb48Bytes[1]; + expected[i6 + 2] = rgb48Bytes[2]; + expected[i6 + 3] = rgb48Bytes[3]; + expected[i6 + 4] = rgb48Bytes[4]; + expected[i6 + 5] = rgb48Bytes[5]; } TestOperation( source, expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) + public void PackFromRgba64Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 8); + Span sourceSpan = source.AsSpan(); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + int i8 = i * 8; + expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); } TestOperation( source, expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToArgb32Bytes(int count) + public void ToRgba64Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var argb = default(Argb32); + byte[] expected = new byte[count * 8]; + Rgba64 rgba = default; for (int i = 0; i < count; i++) { - int i4 = i * 4; - argb.PackFromScaledVector4(source[i].ToScaledVector4()); - - expected[i4] = argb.A; - expected[i4 + 1] = argb.R; - expected[i4 + 2] = argb.G; - expected[i4 + 3] = argb.B; + int i8 = i * 8; + rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + OctetBytes rgba64Bytes = Unsafe.As(ref rgba); + expected[i8] = rgba64Bytes[0]; + expected[i8 + 1] = rgba64Bytes[1]; + expected[i8 + 2] = rgba64Bytes[2]; + expected[i8 + 3] = rgba64Bytes[3]; + expected[i8 + 4] = rgba64Bytes[4]; + expected[i8 + 5] = rgba64Bytes[5]; + expected[i8 + 6] = rgba64Bytes[6]; + expected[i8 + 7] = rgba64Bytes[7]; } TestOperation( source, expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) ); } - private class TestBuffers : IDisposable - where TSource : struct - where TDest : struct - { - public TSource[] SourceBuffer { get; } - public IMemoryOwner ActualDestBuffer { get; } - public TDest[] ExpectedDestBuffer { get; } - - public TestBuffers(TSource[] source, TDest[] expectedDest) - { - this.SourceBuffer = source; - this.ExpectedDestBuffer = expectedDest; - this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); - } - - public void Dispose() => this.ActualDestBuffer.Dispose(); - - private const float Tolerance = 0.0001f; - - public void Verify() - { - int count = this.ExpectedDestBuffer.Length; - - if (typeof(TDest) == typeof(Vector4)) - { - - Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); - Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - - for (int i = 0; i < count; i++) - { - // ReSharper disable PossibleNullReferenceException - Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); - // ReSharper restore PossibleNullReferenceException - } - } - else - { - Span expected = this.ExpectedDestBuffer.AsSpan(); - Span actual = this.ActualDestBuffer.GetSpan(); - for (int i = 0; i < count; i++) - { - Assert.Equal(expected[i], actual[i]); - } - } - } - } - internal static void TestOperation( TSource[] source, TDest[] expected, @@ -666,7 +876,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [StructLayout(LayoutKind.Sequential)] - private unsafe struct Rgba64Bytes + internal unsafe struct OctetBytes { public fixed byte Data[8]; @@ -675,10 +885,56 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ref byte self = ref Unsafe.As(ref this); + ref byte self = ref Unsafe.As(ref this); return Unsafe.Add(ref self, idx); } } } + + private class TestBuffers : IDisposable + where TSource : struct + where TDest : struct + { + public TSource[] SourceBuffer { get; } + public IMemoryOwner ActualDestBuffer { get; } + public TDest[] ExpectedDestBuffer { get; } + + public TestBuffers(TSource[] source, TDest[] expectedDest) + { + this.SourceBuffer = source; + this.ExpectedDestBuffer = expectedDest; + this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); + } + + public void Dispose() => this.ActualDestBuffer.Dispose(); + + public void Verify() + { + int count = this.ExpectedDestBuffer.Length; + + if (typeof(TDest) == typeof(Vector4)) + { + Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); + Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); + + var comparer = new ApproximateFloatComparer(0.001f); + for (int i = 0; i < count; i++) + { + // ReSharper disable PossibleNullReferenceException + Assert.Equal(expected[i], actual[i], comparer); + // ReSharper restore PossibleNullReferenceException + } + } + else + { + Span expected = this.ExpectedDestBuffer.AsSpan(); + Span actual = this.ActualDestBuffer.GetSpan(); + for (int i = 0; i < count; i++) + { + Assert.Equal(expected[i], actual[i]); + } + } + } + } } } \ No newline at end of file From d4bda602ce1739aa03dde5960a6b42fe997b5c00 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Oct 2018 19:53:28 +0100 Subject: [PATCH 017/238] Fix sandbox tests --- tests/ImageSharp.Sandbox46/Program.cs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index fa1d63878a..4d89929a03 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -6,14 +6,9 @@ namespace SixLabors.ImageSharp.Sandbox46 { using System; - using System.Runtime.DesignerServices; - - using SixLabors.ImageSharp.Tests; - using SixLabors.ImageSharp.Tests.Colors; using SixLabors.ImageSharp.Tests.Formats.Jpg; using SixLabors.ImageSharp.Tests.PixelFormats; using SixLabors.ImageSharp.Tests.Processing.Processors.Transforms; - using SixLabors.ImageSharp.Tests.Processing.Transforms; using Xunit.Abstractions; @@ -21,15 +16,9 @@ namespace SixLabors.ImageSharp.Sandbox46 { private class ConsoleOutput : ITestOutputHelper { - public void WriteLine(string message) - { - Console.WriteLine(message); - } + public void WriteLine(string message) => Console.WriteLine(message); - public void WriteLine(string format, params object[] args) - { - Console.WriteLine(format, args); - } + public void WriteLine(string format, params object[] args) => Console.WriteLine(format, args); } /// @@ -58,20 +47,20 @@ namespace SixLabors.ImageSharp.Sandbox46 private static void RunResizeProfilingTest() { - ResizeProfilingBenchmarks test = new ResizeProfilingBenchmarks(new ConsoleOutput()); + var test = new ResizeProfilingBenchmarks(new ConsoleOutput()); test.ResizeBicubic(2000, 2000); } private static void RunToVector4ProfilingTest() { - PixelOperationsTests.Rgba32 tests = new PixelOperationsTests.Rgba32(new ConsoleOutput()); + var tests = new PixelOperationsTests.Rgba32OperationsTests(new ConsoleOutput()); tests.Benchmark_ToVector4(); } private static void RunDecodeJpegProfilingTests() { Console.WriteLine("RunDecodeJpegProfilingTests..."); - JpegProfilingBenchmarks benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); + var benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); foreach (object[] data in JpegProfilingBenchmarks.DecodeJpegData) { string fileName = (string)data[0]; From b14c35ffafe2f762f0ee19cbca34982d638ed039 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Oct 2018 22:29:39 +0100 Subject: [PATCH 018/238] Fix JIT issue on 32bit framework --- src/ImageSharp/PixelFormats/Rgba32.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index e7814d23ac..415c39c0ed 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -133,7 +133,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Rgb24 Rgb { - [MethodImpl(InliningOptions.ShortMethod)] + // If this is changed to ShortMethod then several jpeg encoding tests fail + // on 32 bit Net 4.6.2 and NET 4.7.1 + [MethodImpl(InliningOptions.ColdPath)] get => Unsafe.As(ref this); [MethodImpl(InliningOptions.ShortMethod)] From 3e5325e2b9e580a2617a36c8c3bbacef679f6de4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 16 Oct 2018 00:35:45 +0200 Subject: [PATCH 019/238] uniformize conversion code --- .../SimdUtils.ExtendedIntrinsics.cs | 64 ++++++++++ src/ImageSharp/Common/Extensions/SimdUtils.cs | 50 ++------ .../PixelFormats/Rgba32.PixelOperations.cs | 117 +++--------------- .../Color/Bulk/PackFromVector4.cs | 4 +- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 6 +- .../PixelFormats/PixelOperationsTests.cs | 38 ++---- 6 files changed, 103 insertions(+), 176 deletions(-) create mode 100644 src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs new file mode 100644 index 0000000000..ec52b90eff --- /dev/null +++ b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs @@ -0,0 +1,64 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Methods accelerated only in RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) + /// PR: + /// https://github.com/dotnet/coreclr/pull/10662 + /// API Proposal: + /// https://github.com/dotnet/corefx/issues/15957 + /// + public static class ExtendedIntrinsics + { + public static bool IsAvailable { get; } = +#if NETCOREAPP2_1 +// TODO: Add a build target for .NET 4.7.2 + true; +#else + false; +#endif + + // ReSharper disable once MemberHidesStaticFromOuterClass + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + Guard.IsTrue( + source.Length % Vector.Count == 0, + nameof(source), + "dest.Length should be divisable by Vector.Count!"); + + int n = source.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = Vector.ConvertToSingle(w0) * scale; + Vector f1 = Vector.ConvertToSingle(w1) * scale; + Vector f2 = Vector.ConvertToSingle(w2) * scale; + Vector f3 = Vector.ConvertToSingle(w3) * scale; + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + } + } +} diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs index 481e0726df..3630ede327 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.cs @@ -14,12 +14,12 @@ namespace SixLabors.ImageSharp /// /// Various extension and utility methods for and utilizing SIMD capabilities /// - internal static class SimdUtils + internal static partial class SimdUtils { /// /// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte. /// - public static bool IsAvx2CompatibleArchitecture => Vector.Count == 8 && Vector.Count == 8; + public static bool IsAvx2CompatibleArchitecture { get; } = Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; internal static void GuardAvx2(string operation) { @@ -61,7 +61,8 @@ namespace SixLabors.ImageSharp /// /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of values. - /// The values gonna be scaled up into [0-255] and rounded. + /// The values are scaled up into [0-255] and rounded. + /// The implementation is SIMD optimized and works only with `source.Length` divisible by . /// Based on: /// /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions @@ -106,46 +107,13 @@ namespace SixLabors.ImageSharp } /// - /// Fast -> conversion for RyuJIT runtimes having dotnet/coreclr#10662 merged. + /// Converts `dest.Length` bytes to -s to -s normalized into [0..1] + /// The implementation is SIMD optimized and works only with `dest.Length` divisible by . + /// Implementation adapted from: /// - /// https://github.com/dotnet/coreclr/pull/10662 + /// http://stackoverflow.com/a/5362789 /// /// - internal static void BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(ReadOnlySpan source, Span dest) - { - Guard.IsTrue( - source.Length % Vector.Count == 0, - nameof(source), - "dest.Length should be divisable by Vector.Count!"); - - int n = source.Length / Vector.Count; - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - - var scale = new Vector(1f / 255f); - - for (int i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - Vector f0 = Vector.ConvertToSingle(w0) * scale; - Vector f1 = Vector.ConvertToSingle(w1) * scale; - Vector f2 = Vector.ConvertToSingle(w2) * scale; - Vector f3 = Vector.ConvertToSingle(w3) * scale; - - ref Vector d = ref Unsafe.Add(ref destBase, i * 4); - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; - } - } - internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); @@ -188,7 +156,7 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); + GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 76e119ba44..6745079da5 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -3,7 +3,6 @@ using System; using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.Memory; @@ -19,99 +18,37 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal partial class PixelOperations : PixelOperations { - /// - /// SIMD optimized bulk implementation of - /// that works only with `count` divisible by . - /// - /// The to the source colors. - /// The to the dstination vectors. - /// The number of pixels to convert. - /// - /// Implementation adapted from: - /// - /// http://stackoverflow.com/a/5362789 - /// - /// TODO: We can replace this implementation in the future using new Vector API-s: - /// - /// https://github.com/dotnet/corefx/issues/15957 - /// - /// - internal static void ToVector4SimdAligned(ReadOnlySpan sourceColors, Span destVectors, int count) - { - if (!Vector.IsHardwareAccelerated) - { - throw new InvalidOperationException( - "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); - } - - DebugGuard.IsTrue( - count % Vector.Count == 0, - nameof(count), - "Argument 'count' should divisible by Vector.Count!"); - - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - int unpackedRawCount = count * 4; - - ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); - ref WideRgba destBaseAsWide = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); - ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsWide); - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWide); - - for (int i = 0; i < count; i++) - { - uint sVal = Unsafe.Add(ref sourceBase, i); - ref WideRgba dst = ref Unsafe.Add(ref destBaseAsWide, i); - - // This call is the bottleneck now: - dst.Load(sVal); - } - - int numOfVectors = unpackedRawCount / Vector.Count; - - for (int i = 0; i < numOfVectors; i++) - { - Vector vi = Unsafe.Add(ref destBaseAsUInt, i); - - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - Unsafe.Add(ref destBaseAsFloat, i) = vf; - } - } - /// internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - if (count < 256 || !Vector.IsHardwareAccelerated) + if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) { // Doesn't worth to bother with SIMD: base.ToVector4(sourceColors, destinationVectors, count); return; } - int remainder = count % Vector.Count; + int remainder = count % 2; int alignedCount = count - remainder; if (alignedCount > 0) { - ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount); + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); + Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); + + SimdUtils.BulkConvertByteToNormalizedFloat( + rawSrc, + rawDest); } if (remainder > 0) { - sourceColors = sourceColors.Slice(alignedCount); - destinationVectors = destinationVectors.Slice(alignedCount); - base.ToVector4(sourceColors, destinationVectors, remainder); + // actually: remainder == 1 + int lastIdx = count - 1; + destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); } } @@ -120,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - if (!SimdUtils.IsAvx2CompatibleArchitecture) + if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) { base.PackFromVector4(sourceVectors, destinationColors, count); return; @@ -131,10 +68,10 @@ namespace SixLabors.ImageSharp.PixelFormats if (alignedCount > 0) { - ReadOnlySpan flatSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); - Span flatDest = MemoryMarshal.Cast(destinationColors); + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); + Span rawDest = MemoryMarshal.Cast(destinationColors); - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(flatSrc, flatDest); + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); } if (remainder > 0) @@ -172,30 +109,6 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(dest); } - - /// - /// Value type to store -s widened into multiple -s. - /// - [StructLayout(LayoutKind.Sequential)] - private struct WideRgba - { - private uint r; - - private uint g; - - private uint b; - - private uint a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Load(uint p) - { - this.r = p; - this.g = p >> GreenShift; - this.b = p >> BlueShift; - this.a = p >> AlphaShift; - } - } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index a5fa59ba07..bdae7d0655 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -23,7 +23,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private IMemoryOwner destination; - [Params(16, 128, 512)] + [Params( + //64, + 2048)] public int Count { get; set; } [GlobalSetup] diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 4e39af70fd..0488dd5e15 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -205,12 +205,12 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } - + [Theory] [InlineData(1, 0)] [InlineData(2, 32)] [InlineData(3, 128)] - public void BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(int seed, int count) + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int seed, int count) { if (!Vector.IsHardwareAccelerated) { @@ -221,7 +221,7 @@ namespace SixLabors.ImageSharp.Tests.Common float[] result = new float[count]; float[] expected = source.Select(b => (float)b / 255f).ToArray(); - SimdUtils.BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(source, result); + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(source, result); Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 4d7ec71e72..535952e051 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -17,43 +17,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { public class Rgba32 : PixelOperationsTests { + public const string SkipProfilingBenchmarks = +#if true + "Profiling benchmark - enable manually!"; +#else + null; +#endif + public Rgba32(ITestOutputHelper output) : base(output) { } - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() { Assert.IsType(PixelOperations.Instance); } - [Fact] - public void ToVector4SimdAligned() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) - ); - } - - - // [Fact] // Profiling benchmark - enable manually! -#pragma warning disable xUnit1013 // Public method should be marked as test + [Fact(Skip = SkipProfilingBenchmarks)] public void Benchmark_ToVector4() -#pragma warning restore xUnit1013 // Public method should be marked as test { int times = 200000; int count = 1024; @@ -73,13 +56,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public class Argb32 : PixelOperationsTests { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: public Argb32(ITestOutputHelper output) : base(output) { } - - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; } [Theory] @@ -110,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 1111 }; private static PixelOperations Operations => PixelOperations.Instance; From df87a68555b480e58e886e6f9d2513db29c8d5fd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 16 Oct 2018 01:02:39 +0200 Subject: [PATCH 020/238] BulkConvertNormalizedFloatToByteClampOverflows --- .../SimdUtils.ExtendedIntrinsics.cs | 66 +++++++++++++++++-- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 18 +++++ 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs index ec52b90eff..97f364a109 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs @@ -24,6 +24,9 @@ namespace SixLabors.ImageSharp false; #endif + /// + /// A variant of , which is faster on new .NET runtime. + /// // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { @@ -37,7 +40,7 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - var scale = new Vector(1f / 255f); + const float Scale = 1f / 255f; for (int i = 0; i < n; i++) { @@ -47,10 +50,10 @@ namespace SixLabors.ImageSharp Vector.Widen(s0, out Vector w0, out Vector w1); Vector.Widen(s1, out Vector w2, out Vector w3); - Vector f0 = Vector.ConvertToSingle(w0) * scale; - Vector f1 = Vector.ConvertToSingle(w1) * scale; - Vector f2 = Vector.ConvertToSingle(w2) * scale; - Vector f3 = Vector.ConvertToSingle(w3) * scale; + Vector f0 = Vector.ConvertToSingle(w0) * Scale; + Vector f1 = Vector.ConvertToSingle(w1) * Scale; + Vector f2 = Vector.ConvertToSingle(w2) * Scale; + Vector f3 = Vector.ConvertToSingle(w3) * Scale; ref Vector d = ref Unsafe.Add(ref destBase, i * 4); d = f0; @@ -59,6 +62,59 @@ namespace SixLabors.ImageSharp Unsafe.Add(ref d, 3) = f3; } } + + /// + /// A variant of , which is faster on new .NET runtime. + /// + // ReSharper disable once MemberHidesStaticFromOuterClass + internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + { + Guard.IsTrue( + dest.Length % Vector.Count == 0, + nameof(source), + "dest.Length should be divisable by Vector.Count!"); + + int n = dest.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + for (int i = 0; i < n; i++) + { + ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); + + Vector f0 = s; + f0 = Clamp(f0); + + Vector f1 = Unsafe.Add(ref s, 1); + f1 = Clamp(f1); + + Vector f2 = Unsafe.Add(ref s, 2); + f2 = Clamp(f2); + + Vector f3 = Unsafe.Add(ref s, 3); + f3 = Clamp(f3); + + Vector w0 = Vector.ConvertToUInt32(f0 * 255f); + Vector w1 = Vector.ConvertToUInt32(f1 * 255f); + Vector w2 = Vector.ConvertToUInt32(f2 * 255f); + Vector w3 = Vector.ConvertToUInt32(f3 * 255f); + + Vector u0 = Vector.Narrow(w0, w1); + Vector u1 = Vector.Narrow(w2, w3); + + Vector b = Vector.Narrow(u0, u1); + + Unsafe.Add(ref destBase, i) = b; + } + + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector Clamp(Vector x) + { + return Vector.Min(Vector.Max(x, Vector.Zero), Vector.One); + } } } } diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 0488dd5e15..4b23ca30f1 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -226,6 +226,24 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } + [Theory] + [InlineData(1, 0)] + [InlineData(2, 32)] + [InlineData(3, 128)] + public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count) + { + float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444); + float[] normalized = orig.Select(f => f / 255f).ToArray(); + + byte[] dest = new byte[count]; + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest); + + byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray(); + + Assert.Equal(expected, dest); + } + [Theory] [InlineData(0)] [InlineData(7)] From b8b411bb716664d840d08f96759cec91f4f471d4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 16 Oct 2018 01:13:43 +0200 Subject: [PATCH 021/238] disappointing benchmark results --- .../SimdUtils.ExtendedIntrinsics.cs | 5 +- .../Color/Bulk/PackFromVector4.cs | 48 +++++++++++++++++-- .../Color/Bulk/ToVector4.cs | 6 +-- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs index 97f364a109..90048ca9b4 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs @@ -66,6 +66,10 @@ namespace SixLabors.ImageSharp /// /// A variant of , which is faster on new .NET runtime. /// + /// + /// It does NOT worth yet to utilize this method (2018 Oct). + /// See benchmark results for the "PackFromVector4_Rgba32" benchmark! + /// // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { @@ -107,7 +111,6 @@ namespace SixLabors.ImageSharp Unsafe.Add(ref destBase, i) = b; } - } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index bdae7d0655..4bf98e5ceb 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -3,6 +3,7 @@ // ReSharper disable InconsistentNaming +using System; using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; @@ -19,9 +20,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public abstract class PackFromVector4 where TPixel : struct, IPixel { - private IMemoryOwner source; + protected IMemoryOwner source; - private IMemoryOwner destination; + protected IMemoryOwner destination; [Params( //64, @@ -42,7 +43,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.Dispose(); } - [Benchmark(Baseline = true)] + [Benchmark] public void PerElement() { ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan()); @@ -54,7 +55,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + [Benchmark(Baseline = true)] public void CommonBulk() { new PixelOperations().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); @@ -69,6 +70,45 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class PackFromVector4_Rgba32 : PackFromVector4 { + //[Benchmark] + public void BulkConvertNormalizedFloatToByteClampOverflows() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + + [Benchmark] + public void ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + // RESULTS: + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC + // .NET Core SDK=2.1.400-preview-009063 + // [Host] : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT + // Job-XIFINS : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-RTQZPN : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT + // + // LaunchCount=1 TargetCount=3 WarmupCount=3 + // + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------------------------------- |-------- |------ |----------:|-----------:|----------:|-------:|---------:|----------:| + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3.755 us | 0.8959 us | 0.0506 us | 0.22 | 0.00 | 0 B | + // PerElement | Clr | 2048 | 17.387 us | 15.1569 us | 0.8564 us | 1.02 | 0.04 | 0 B | + // CommonBulk | Clr | 2048 | 17.121 us | 0.7634 us | 0.0431 us | 1.00 | 0.00 | 24 B | + // OptimizedBulk | Clr | 2048 | 4.018 us | 0.3858 us | 0.0218 us | 0.23 | 0.00 | 0 B | + // | | | | | | | | | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 22.232 us | 1.6154 us | 0.0913 us | 1.31 | 0.04 | 0 B | + // PerElement | Core | 2048 | 16.741 us | 2.9254 us | 0.1653 us | 0.98 | 0.03 | 0 B | + // CommonBulk | Core | 2048 | 17.022 us | 11.4894 us | 0.6492 us | 1.00 | 0.00 | 24 B | + // OptimizedBulk | Core | 2048 | 3.707 us | 0.1500 us | 0.0085 us | 0.22 | 0.01 | 0 B | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 3ea256e85a..39c1fbd474 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { } - //[Benchmark] + [Benchmark] public void BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -89,12 +89,12 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void BulkConvertByteToNormalizedFloatFast() + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertByteToNormalizedFloatWithExtendedIntrinsics(sBytes, dFloats); + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } } From 778895b44beb1b20aa257abb415e6a5a009a0994 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 16 Oct 2018 13:41:58 +0100 Subject: [PATCH 022/238] Use FormattableString --- src/ImageSharp/PixelFormats/Bgr565.cs | 2 +- src/ImageSharp/PixelFormats/Bgra4444.cs | 2 +- src/ImageSharp/PixelFormats/Bgra5551.cs | 2 +- src/ImageSharp/PixelFormats/Byte4.cs | 2 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 3 ++- src/ImageSharp/PixelFormats/HalfVector2.cs | 3 ++- src/ImageSharp/PixelFormats/HalfVector4.cs | 3 ++- src/ImageSharp/PixelFormats/NormalizedByte2.cs | 2 +- src/ImageSharp/PixelFormats/NormalizedByte4.cs | 2 +- src/ImageSharp/PixelFormats/NormalizedShort2.cs | 2 +- src/ImageSharp/PixelFormats/NormalizedShort4.cs | 2 +- src/ImageSharp/PixelFormats/Rg32.cs | 2 +- src/ImageSharp/PixelFormats/Rgba1010102.cs | 6 +++++- src/ImageSharp/PixelFormats/RgbaVector.cs | 3 ++- src/ImageSharp/PixelFormats/Short2.cs | 2 +- src/ImageSharp/PixelFormats/Short4.cs | 2 +- 16 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 454f458b12..04af6ef0f1 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -148,7 +148,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector3(); - return $"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"; + return FormattableString.Invariant($"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index 08484eba8d..db1c8f865a 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index df0a467301..5d9003cdd3 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index 34546e0271..230c31c5c3 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index 78edc9a08e..bef4a5dd9b 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -130,7 +131,7 @@ namespace SixLabors.ImageSharp.PixelFormats public bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() => $"HalfSingle({this.ToSingle():#0.##})"; + public override string ToString() => FormattableString.Invariant($"HalfSingle({this.ToSingle():#0.##})"); /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index e3777bc2fb..5bd9924c53 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -150,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 079c3ee383..2e487ef985 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -145,7 +146,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 3eaa69c03e..219ec87630 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index e0e3e65020..d5795cb4bd 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 0aa5736379..34e752496a 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 577e901544..6fda84bc2e 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index 02c294b4ff..0831f6524e 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 86b639e229..14265b54e9 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -135,7 +135,11 @@ namespace SixLabors.ImageSharp.PixelFormats public bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue; /// - public override string ToString() => this.ToVector4().ToString(); + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"Rgba1010102({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index b5ccf8aedc..b2a3dc578e 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -189,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"; + return FormattableString.Invariant($"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"); } /// diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index db29b401ed..81df3ef7b9 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector2(); - return $"Short2({vector.X:#0.##}, {vector.Y:#0.##})"; + return FormattableString.Invariant($"Short2({vector.X:#0.##}, {vector.Y:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 6d6e5f0845..48bd01d6e1 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.PixelFormats public override string ToString() { var vector = this.ToVector4(); - return $"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"; + return FormattableString.Invariant($"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } [MethodImpl(InliningOptions.ShortMethod)] From 1daa463fd261df0a952766d39c3bb6e9e5d626f2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 16 Oct 2018 14:26:40 +0100 Subject: [PATCH 023/238] Use new IPixel API --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 24 +++------ src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 34 +++++++++---- .../Formats/Png/PngScanlineProcessor.cs | 51 +++++-------------- 3 files changed, 45 insertions(+), 64 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 71852acddd..dabab651d0 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -219,8 +219,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp where TPixel : struct, IPixel { TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); - using (Buffer2D buffer = this.memoryAllocator.Allocate2D(width, height, AllocationOptions.Clean)) { this.UncompressRle8(width, buffer.GetSpan()); @@ -233,8 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int x = 0; x < width; x++) { - rgba.Bgr = Unsafe.As(ref colors[bufferRow[x] * 4]); - color.PackFromRgba32(rgba); + color.PackFromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); pixelRow[x] = color; } } @@ -352,8 +349,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean)) { TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); - Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) @@ -363,7 +358,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp int offset = 0; Span pixelRow = pixels.GetRowSpan(newY); - // TODO: Could use PixelOperations here! for (int x = 0; x < arrayWidth; x++) { int colOffset = x * ppb; @@ -371,9 +365,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; - // Stored in b-> g-> r order. - rgba.Bgr = Unsafe.As(ref colors[colorIndex]); - color.PackFromRgba32(rgba); + color.PackFromBgr24(Unsafe.As(ref colors[colorIndex])); pixelRow[newX] = color; } @@ -397,7 +389,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp int padding = CalculatePadding(width, 2); int stride = (width * 2) + padding; TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride)) { @@ -412,11 +403,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp { short temp = BitConverter.ToInt16(buffer.Array, offset); - rgba.R = GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10); - rgba.G = GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5); - rgba.B = GetBytesFrom5BitValue(temp & Rgb16BMask); + var rgb = new Rgb24( + GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10), + GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5), + GetBytesFrom5BitValue(temp & Rgb16BMask)); - color.PackFromRgba32(rgba); + color.PackFromRgb24(rgb); pixelRow[x] = color; offset += 2; } @@ -537,7 +529,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.metaData = meta; short bitsPerPixel = this.infoHeader.BitsPerPixel; - var bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); + BmpMetaData bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); // We can only encode at these bit rates so far. if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 207f126f9e..155e6484f7 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -481,22 +481,36 @@ namespace SixLabors.ImageSharp.Formats.Gif } ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY)); - var rgba = new Rgba32(0, 0, 0, 255); + bool transFlag = this.graphicsControlExtension.TransparencyFlag; - // #403 The left + width value can be larger than the image width - for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + if (!transFlag) { - int index = Unsafe.Add(ref indicesRef, i); - - if (!this.graphicsControlExtension.TransparencyFlag - || this.graphicsControlExtension.TransparencyIndex != index) + // #403 The left + width value can be larger than the image width + for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) { + int index = Unsafe.Add(ref indicesRef, i); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); - rgba.Rgb = colorTable[index]; - pixel.PackFromRgba32(rgba); + Rgb24 rgb = colorTable[index]; + pixel.PackFromRgb24(rgb); + + i++; } + } + else + { + byte transIndex = this.graphicsControlExtension.TransparencyIndex; + for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + { + int index = Unsafe.Add(ref indicesRef, i); + if (transIndex != index) + { + ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); + Rgb24 rgb = colorTable[index]; + pixel.PackFromRgb24(rgb); + } - i++; + i++; + } } } diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 6c81ba76c2..92c76a3fa2 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -32,30 +32,19 @@ namespace SixLabors.ImageSharp.Formats.Png { if (header.BitDepth == 16) { - Rgb48 rgb48 = default; for (int x = 0, o = 0; x < header.Width; x++, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.R = luminance; - rgb48.G = luminance; - rgb48.B = luminance; - - pixel.PackFromRgb48(rgb48); + pixel.PackFromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. - var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = 0; x < header.Width; x++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - - pixel.PackFromRgba32(rgba32); + pixel.PackFromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -115,30 +104,19 @@ namespace SixLabors.ImageSharp.Formats.Png { if (header.BitDepth == 16) { - Rgb48 rgb48 = default; for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.R = luminance; - rgb48.G = luminance; - rgb48.B = luminance; - - pixel.PackFromRgb48(rgb48); + pixel.PackFromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. - var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - - pixel.PackFromRgba32(rgba32); + pixel.PackFromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -309,14 +287,12 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - // TODO: We should have PackFromRgb24. - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = 0; x < header.Width; x++) { int index = Unsafe.Add(ref scanlineSpanRef, x); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.PackFromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -356,13 +332,12 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) { int index = Unsafe.Add(ref scanlineSpanRef, o); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.PackFromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -509,14 +484,14 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); + Rgb24 rgb = default; for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) { - rgba.R = Unsafe.Add(ref scanlineSpanRef, o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); - rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); + rgb.R = Unsafe.Add(ref scanlineSpanRef, o); + rgb.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); + rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); - pixel.PackFromRgba32(rgba); + pixel.PackFromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } From a4714207e03a0a8f92d0ee95751eb8693ef3a14e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 17 Oct 2018 23:39:29 +0200 Subject: [PATCH 024/238] todo notes --- .../Common/Extensions/SimdUtils.ExtendedIntrinsics.cs | 1 + tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs index 90048ca9b4..fba54b033a 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs @@ -69,6 +69,7 @@ namespace SixLabors.ImageSharp /// /// It does NOT worth yet to utilize this method (2018 Oct). /// See benchmark results for the "PackFromVector4_Rgba32" benchmark! + /// TODO: Check again later! /// // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index 4bf98e5ceb..fb505ddcbd 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -88,7 +88,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } + // TODO: Check again later! // RESULTS: + // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores // Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC From fbde4f32fd501542d99e59c639d3f1154174240e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 18 Oct 2018 17:04:41 +0100 Subject: [PATCH 025/238] Use scaled luminance trns comparison. --- .../Formats/Png/PngScanlineProcessor.cs | 6 ++++-- .../Formats/Png/PngDecoderTests.cs | 3 ++- tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Png/gray-1-trns.png | Bin 0 -> 366 bytes 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 tests/Images/Input/Png/gray-1-trns.png diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 6c81ba76c2..5ea25e72d4 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -80,6 +80,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { + byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor); Rgba32 rgba32 = default; for (int x = 0; x < header.Width; x++) { @@ -87,7 +88,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; - rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; + rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; pixel.PackFromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -163,6 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { + byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor); Rgba32 rgba32 = default; for (int x = pixelOffset; x < header.Width; x += increment) { @@ -170,7 +172,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; - rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; + rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; pixel.PackFromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 54f3e397c3..f51f9b6c5c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -40,7 +40,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png TestImages.Png.VimImage2, TestImages.Png.Rgb24BppTrans, - TestImages.Png.GrayAlpha8Bit + TestImages.Png.GrayAlpha8Bit, + TestImages.Png.Gray1BitTrans }; public static readonly string[] TestImages48Bpp = diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index fdf586c430..758f256345 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -45,6 +45,7 @@ namespace SixLabors.ImageSharp.Tests public const string Kaboom = "Png/kaboom.png"; public const string PDSrc = "Png/pd-source.png"; public const string PDDest = "Png/pd-dest.png"; + public const string Gray1BitTrans = "Png/gray-1-trns.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/Images/Input/Png/gray-1-trns.png b/tests/Images/Input/Png/gray-1-trns.png new file mode 100644 index 0000000000000000000000000000000000000000..99b288d52666f930ba760226e0687fd16c18e967 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0y~yVAN$`VCrH73NSci8gu|Drjj7PU~)y|GZ}kOL3P1p|(h`kCj~HI)TOcnDs2`|;Yn&D&2d zc^7STeg3AM*X9_!nQ1%k9^2s!>o-0rI$*$ac*DU6>$&Pc+F)ADDv7qN_JtVTp*E8bj_RaPgn@lz~JfX=d#Wzp$Pzp C@PiTn literal 0 HcmV?d00001 From 9b196316d687d40e2a1d735eb58cb8e25000aceb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 18 Oct 2018 22:45:39 +0200 Subject: [PATCH 026/238] common fixtures for PixelConversion* benchmarks --- .../General/PixelConversion/ITestPixel.cs | 24 ++++++ .../PixelConversion_ConvertFromRgba32.cs | 81 ++----------------- .../PixelConversion_ConvertFromVector4.cs | 53 ++++-------- .../PixelConversion_ConvertToRgba32.cs | 59 ++------------ .../General/PixelConversion/TestArgb.cs | 74 +++++++++++++++++ .../General/PixelConversion/TestRgba.cs | 57 +++++++++++++ 6 files changed, 181 insertions(+), 167 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs rename tests/ImageSharp.Benchmarks/General/{ => PixelConversion}/PixelConversion_ConvertFromRgba32.cs (66%) rename tests/ImageSharp.Benchmarks/General/{ => PixelConversion}/PixelConversion_ConvertFromVector4.cs (75%) rename tests/ImageSharp.Benchmarks/General/{ => PixelConversion}/PixelConversion_ConvertToRgba32.cs (68%) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs new file mode 100644 index 0000000000..ede617032f --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs @@ -0,0 +1,24 @@ +using System.Numerics; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + interface ITestPixel + where T : struct, ITestPixel + { + void FromRgba32(Rgba32 source); + + void FromRgba32(ref Rgba32 source); + + void FromBytes(byte r, byte g, byte b, byte a); + + void FromVector4(Vector4 source); + + void FromVector4(ref Vector4 source); + + Rgba32 ToRgba32(); + + void CopyToRgba32(ref Rgba32 dest); + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs similarity index 66% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index f5bd135e12..046c7dd90c 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -1,86 +1,15 @@ // ReSharper disable InconsistentNaming -using SixLabors.ImageSharp.PixelFormats; +using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; - using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ public class PixelConversion_ConvertFromRgba32 { - interface ITestPixel - where T : struct, ITestPixel - { - void FromRgba32(Rgba32 source); - - void FromRgba32(ref Rgba32 source); - - void FromBytes(byte r, byte g, byte b, byte a); - } - - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 p) - { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 p) - { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgba : ITestPixel - { - private byte r, g, b, a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 source) - { - this = Unsafe.As(ref source); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 source) - { - this = Unsafe.As(ref source); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - } - struct ConversionRunner where T : struct, ITestPixel { diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs similarity index 75% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs index 5b059e2e65..30af857b1d 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs @@ -1,46 +1,17 @@ // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Numerics; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - - using BenchmarkDotNet.Attributes; - - public class PixelConversion_ConvertFromVector4 - { - interface ITestPixel - where T : struct, ITestPixel - { - void FromVector4(Vector4 source); - - void FromVector4(ref Vector4 source); - } - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(Vector4 p) - { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; - } +using BenchmarkDotNet.Attributes; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(ref Vector4 p) - { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; - } - } +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertFromVector4 + { [StructLayout(LayoutKind.Sequential)] struct TestRgbaVector : ITestPixel { @@ -57,6 +28,12 @@ namespace SixLabors.ImageSharp.Benchmarks.General { this.v = p; } + + public void FromRgba32(Rgba32 source) => throw new System.NotImplementedException(); + public void FromRgba32(ref Rgba32 source) => throw new System.NotImplementedException(); + public void FromBytes(byte r, byte g, byte b, byte a) => throw new System.NotImplementedException(); + public Rgba32 ToRgba32() => throw new System.NotImplementedException(); + public void CopyToRgba32(ref Rgba32 dest) => throw new System.NotImplementedException(); } struct ConversionRunner diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs similarity index 68% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs index 5656904fe0..89b4031a85 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs @@ -1,14 +1,14 @@ // ReSharper disable InconsistentNaming -using SixLabors.ImageSharp.PixelFormats; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; - using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ /// /// When implementing TPixel --> Rgba32 style conversions on IPixel, should which API should we prefer? /// 1. Rgba32 ToRgba32(); @@ -18,53 +18,6 @@ namespace SixLabors.ImageSharp.Benchmarks.General /// public class PixelConversion_ConvertToRgba32 { - interface ITestPixel - where T : struct, ITestPixel - { - Rgba32 ToRgba32(); - - void CopyToRgba32(ref Rgba32 dest); - } - - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return new Rgba32(this.r, this.g, this.b, this.a); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest.R = this.r; - dest.G = this.g; - dest.B = this.b; - dest.A = this.a; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgba : ITestPixel - { - private byte r, g, b, a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return Unsafe.As(ref this); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest = Unsafe.As(ref this); - } - } - struct ConversionRunner where T : struct, ITestPixel { diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs new file mode 100644 index 0000000000..ddac1d1052 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -0,0 +1,74 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + [StructLayout(LayoutKind.Sequential)] + struct TestArgb : ITestPixel + { + private byte a, r, g, b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 p) + { + this.r = p.R; + this.g = p.G; + this.b = p.B; + this.a = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 p) + { + this.r = p.R; + this.g = p.G; + this.b = p.B; + this.a = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 p) + { + this.r = (byte)p.X; + this.g = (byte)p.Y; + this.b = (byte)p.Z; + this.a = (byte)p.W; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 p) + { + this.r = (byte)p.X; + this.g = (byte)p.Y; + this.b = (byte)p.Z; + this.a = (byte)p.W; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return new Rgba32(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest.R = this.r; + dest.G = this.g; + dest.B = this.b; + dest.A = this.a; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs new file mode 100644 index 0000000000..b06e84063f --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -0,0 +1,57 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + [StructLayout(LayoutKind.Sequential)] + struct TestRgba : ITestPixel + { + private byte r, g, b, a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public void FromVector4(Vector4 source) + { + throw new System.NotImplementedException(); + } + + public void FromVector4(ref Vector4 source) + { + throw new System.NotImplementedException(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest = Unsafe.As(ref this); + } + } +} \ No newline at end of file From 3051d718a370aa5c33622461729d33e491eb3d99 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 18 Oct 2018 22:56:02 +0200 Subject: [PATCH 027/238] PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation --- ...vertToRgba32_AsPartOfCompositeOperation.cs | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs new file mode 100644 index 0000000000..a27f7c3a5d --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs @@ -0,0 +1,113 @@ +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Rgba32[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Rgba32[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + Rgba32 temp; + + for (int i = 0; i < count; i++) + { + temp = Unsafe.Add(ref sourceBaseRef, i).ToRgba32(); + + // manipulate pixel before saving to dest buffer: + temp.A = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + Rgba32 temp = default; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToRgba32(ref temp); + + // manipulate pixel before saving to dest buffer: + temp.A = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + } + + private ConversionRunner compatibleMemoryLayoutRunner; + + private ConversionRunner permutedRunner; + + [Params(128)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.compatibleMemoryLayoutRunner = new ConversionRunner(this.Count); + this.permutedRunner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void CompatibleRetval() + { + this.compatibleMemoryLayoutRunner.RunRetvalConversion(); + } + + [Benchmark] + public void CompatibleCopyTo() + { + this.compatibleMemoryLayoutRunner.RunCopyToConversion(); + } + + [Benchmark] + public void PermutedRetval() + { + this.permutedRunner.RunRetvalConversion(); + } + + [Benchmark] + public void PermutedCopyTo() + { + this.permutedRunner.RunCopyToConversion(); + } + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ----------------- |------ |-----------:|----------:|----------:|-------:|---------:| + // CompatibleRetval | 128 | 210.1 ns | 0.8443 ns | 0.7484 ns | 1.00 | 0.00 | + // CompatibleCopyTo | 128 | 140.1 ns | 0.4297 ns | 0.4019 ns | 0.67 | 0.00 | + // PermutedRetval | 128 | 1,044.6 ns | 3.7901 ns | 3.3599 ns | 4.97 | 0.02 | + // PermutedCopyTo | 128 | 140.3 ns | 0.6495 ns | 0.5757 ns | 0.67 | 0.00 | +} \ No newline at end of file From 9ab574c63369b3c68372ed28a3175e6735f09316 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 18 Oct 2018 23:13:44 +0200 Subject: [PATCH 028/238] benchmarks for TPixel -> Vector4 conversion --- .../General/PixelConversion/ITestPixel.cs | 4 + .../PixelConversion_ConvertFromVector4.cs | 9 ++ .../PixelConversion_ConvertToRgba32.cs | 2 +- ...vertToRgba32_AsPartOfCompositeOperation.cs | 14 +-- .../PixelConversion_ConvertToVector4.cs | 83 ++++++++++++++++ ...ertToVector4_AsPartOfCompositeOperation.cs | 95 +++++++++++++++++++ .../General/PixelConversion/TestArgb.cs | 15 +++ .../General/PixelConversion/TestRgba.cs | 15 +++ 8 files changed, 229 insertions(+), 8 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs index ede617032f..b5f339fb37 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs @@ -20,5 +20,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion Rgba32 ToRgba32(); void CopyToRgba32(ref Rgba32 dest); + + Vector4 ToVector4(); + + void CopyToVector4(ref Vector4 dest); } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs index 30af857b1d..d0c8a3045c 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs @@ -29,6 +29,15 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion this.v = p; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() => this.v; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + dest = this.v; + } + public void FromRgba32(Rgba32 source) => throw new System.NotImplementedException(); public void FromRgba32(ref Rgba32 source) => throw new System.NotImplementedException(); public void FromBytes(byte r, byte g, byte b, byte a) => throw new System.NotImplementedException(); diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs index 89b4031a85..d205e1e63e 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion private ConversionRunner permutedRunner; - [Params(128)] + [Params(32)] public int Count { get; set; } [GlobalSetup] diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs index a27f7c3a5d..fff9ae9bc7 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion private ConversionRunner permutedRunner; - [Params(128)] + [Params(32)] public int Count { get; set; } [GlobalSetup] @@ -104,10 +104,10 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | - // ----------------- |------ |-----------:|----------:|----------:|-------:|---------:| - // CompatibleRetval | 128 | 210.1 ns | 0.8443 ns | 0.7484 ns | 1.00 | 0.00 | - // CompatibleCopyTo | 128 | 140.1 ns | 0.4297 ns | 0.4019 ns | 0.67 | 0.00 | - // PermutedRetval | 128 | 1,044.6 ns | 3.7901 ns | 3.3599 ns | 4.97 | 0.02 | - // PermutedCopyTo | 128 | 140.3 ns | 0.6495 ns | 0.5757 ns | 0.67 | 0.00 | + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ----------------- |------ |----------:|----------:|----------:|-------:|---------:| + // CompatibleRetval | 32 | 53.05 ns | 0.1865 ns | 0.1557 ns | 1.00 | 0.00 | + // CompatibleCopyTo | 32 | 36.12 ns | 0.3596 ns | 0.3003 ns | 0.68 | 0.01 | + // PermutedRetval | 32 | 303.61 ns | 5.1697 ns | 4.8358 ns | 5.72 | 0.09 | + // PermutedCopyTo | 32 | 38.05 ns | 0.8053 ns | 1.2297 ns | 0.72 | 0.02 | } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs new file mode 100644 index 0000000000..29a1139912 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs @@ -0,0 +1,83 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToVector4 + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Vector4[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Vector4[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i) = Unsafe.Add(ref sourceBaseRef, i).ToVector4(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref Unsafe.Add(ref destBaseRef, i)); + } + } + } + + private ConversionRunner runner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.runner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void UseRetval() + { + this.runner.RunRetvalConversion(); + } + + [Benchmark] + public void UseCopyTo() + { + this.runner.RunCopyToConversion(); + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // ---------- |------ |---------:|----------:|----------:|-------:| + // UseRetval | 32 | 94.99 ns | 1.1199 ns | 0.9352 ns | 1.00 | + // UseCopyTo | 32 | 59.47 ns | 0.6104 ns | 0.5710 ns | 0.63 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs new file mode 100644 index 0000000000..e5eb5c6cad --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs @@ -0,0 +1,95 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToVector4_AsPartOfCompositeOperation + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Vector4[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Vector4[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + Vector4 temp; + + for (int i = 0; i < count; i++) + { + temp = Unsafe.Add(ref sourceBaseRef, i).ToVector4(); + + // manipulate pixel before saving to dest buffer: + temp.W = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + Vector4 temp = default; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref temp); + + // manipulate pixel before saving to dest buffer: + temp.W = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + } + + private ConversionRunner runner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.runner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void UseRetval() + { + this.runner.RunRetvalConversion(); + } + + [Benchmark] + public void UseCopyTo() + { + this.runner.RunCopyToConversion(); + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // ---------- |------ |----------:|----------:|----------:|-------:| + // UseRetval | 32 | 100.35 ns | 0.4844 ns | 0.4532 ns | 1.00 | + // UseCopyTo | 32 | 53.95 ns | 0.1269 ns | 0.1125 ns | 0.54 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs index ddac1d1052..61a7df81d6 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -70,5 +70,20 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion dest.B = this.b; dest.A = this.a; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + dest.X = this.r; + dest.Y = this.g; + dest.Z = this.b; + dest.W = this.a; + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index b06e84063f..3da7fcc4cf 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -53,5 +53,20 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { dest = Unsafe.As(ref this); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.r, this.g, this.b, this.a); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + dest.X = this.r; + dest.Y = this.g; + dest.Z = this.b; + dest.W = this.a; + } } } \ No newline at end of file From 0f4f8227907fd142b092a112737b5ace6c50c21a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 19 Oct 2018 13:14:33 +0200 Subject: [PATCH 029/238] cleanup --- .../SimdUtils.ExtendedIntrinsics.cs | 32 +++-- .../{Extensions => Helpers}/SimdUtils.cs | 18 +-- .../PixelFormats/PixelOperations{TPixel}.cs | 56 +++++---- .../PixelFormats/Rgba32.PixelOperations.cs | 69 ++++++++--- .../Color/Bulk/ToVector4.cs | 112 ++++++++++++++++-- .../PixelFormats/PixelOperationsTests.cs | 2 +- 6 files changed, 220 insertions(+), 69 deletions(-) rename src/ImageSharp/Common/{Extensions => Helpers}/SimdUtils.ExtendedIntrinsics.cs (81%) rename src/ImageSharp/Common/{Extensions => Helpers}/SimdUtils.cs (96%) diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs similarity index 81% rename from src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs rename to src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index fba54b033a..6def8938a9 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp { public static bool IsAvailable { get; } = #if NETCOREAPP2_1 -// TODO: Add a build target for .NET 4.7.2 +// TODO: Also available in .NET 4.7.2, we need to add a build target! true; #else false; @@ -31,14 +31,15 @@ namespace SixLabors.ImageSharp internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { Guard.IsTrue( - source.Length % Vector.Count == 0, + dest.Length % Vector.Count == 0, nameof(source), "dest.Length should be divisable by Vector.Count!"); - int n = source.Length / Vector.Count; + int n = dest.Length / Vector.Count; ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); const float Scale = 1f / 255f; @@ -50,16 +51,23 @@ namespace SixLabors.ImageSharp Vector.Widen(s0, out Vector w0, out Vector w1); Vector.Widen(s1, out Vector w2, out Vector w3); - Vector f0 = Vector.ConvertToSingle(w0) * Scale; - Vector f1 = Vector.ConvertToSingle(w1) * Scale; - Vector f2 = Vector.ConvertToSingle(w2) * Scale; - Vector f3 = Vector.ConvertToSingle(w3) * Scale; + ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + + n = dest.Length / Vector.Count; + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBase, i); + ref Vector du = ref Unsafe.As, Vector>(ref df); - ref Vector d = ref Unsafe.Add(ref destBase, i * 4); - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; + Vector v = Vector.ConvertToSingle(du); + v *= Scale; + df = v; } } diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs similarity index 96% rename from src/ImageSharp/Common/Extensions/SimdUtils.cs rename to src/ImageSharp/Common/Helpers/SimdUtils.cs index 3630ede327..91aed8c79a 100644 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -2,13 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.PixelFormats; - namespace SixLabors.ImageSharp { /// @@ -131,23 +128,26 @@ namespace SixLabors.ImageSharp ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); int n = dest.Length / 8; - Octet.OfUInt32 temp = default; for (int i = 0; i < n; i++) { - Octet.OfByte sVal = Unsafe.Add(ref sourceBase, i); + ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); + d.LoadFrom(ref s); + } - // This call is the bottleneck now: - temp.LoadFrom(ref sVal); + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); - Vector vi = Unsafe.As>(ref temp); + var vi = Vector.AsVectorUInt32(df); vi &= mask; vi |= magicInt; var vf = Vector.AsVectorSingle(vi); vf = (vf - magicFloat) * bVec; - Unsafe.Add(ref destBaseAsFloat, i) = vf; + df = vf; } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index b12a2bfa58..39c442fe02 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -29,17 +29,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - - for (int i = 0; i < count; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromVector4(sp); - } + PackFromVector4Common(sourceVectors, destinationColors, count); } /// @@ -50,17 +40,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); - - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } + ToVector4Common(sourceColors, destinationVectors, count); } /// @@ -126,5 +106,37 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName); } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void PackFromVector4Common(ReadOnlySpan sourceVectors, Span destinationColors, int count) + { + GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + + for (int i = 0; i < count; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ToVector4Common(ReadOnlySpan sourceColors, Span destinationVectors, int count) + { + GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 6745079da5..0b96a599b6 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -27,28 +27,17 @@ namespace SixLabors.ImageSharp.PixelFormats if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) { // Doesn't worth to bother with SIMD: - base.ToVector4(sourceColors, destinationVectors, count); + ToVector4Common(sourceColors, destinationVectors, count); return; } - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) + if (SimdUtils.ExtendedIntrinsics.IsAvailable) { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); - Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); - - SimdUtils.BulkConvertByteToNormalizedFloat( - rawSrc, - rawDest); + ConvertToVector4UsingExtendedIntrinsics(sourceColors, destinationVectors, count); } - - if (remainder > 0) + else { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); + ConvertToVector4UsingStandardIntrinsics(sourceColors, destinationVectors, count); } } @@ -59,7 +48,7 @@ namespace SixLabors.ImageSharp.PixelFormats if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) { - base.PackFromVector4(sourceVectors, destinationColors, count); + PackFromVector4Common(sourceVectors, destinationColors, count); return; } @@ -109,6 +98,52 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(dest); } + + private static void ConvertToVector4UsingExtendedIntrinsics( + ReadOnlySpan sourceColors, + Span destinationVectors, + int count) + { + int remainder = count % 8; + int alignedCount = count - remainder; + + if (alignedCount > 0) + { + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); + Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); + + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); + } + + if (remainder > 0) + { + ToVector4Common(sourceColors.Slice(alignedCount), destinationVectors.Slice(alignedCount), remainder); + } + } + + private static void ConvertToVector4UsingStandardIntrinsics( + ReadOnlySpan sourceColors, + Span destinationVectors, + int count) + { + int remainder = count % 2; + int alignedCount = count - remainder; + + if (alignedCount > 0) + { + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); + Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); + + SimdUtils.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); + } + + if (remainder > 0) + { + // actually: remainder == 1 + int lastIdx = count - 1; + destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); + } + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 39c1fbd474..6afd3cf6b1 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -6,6 +6,7 @@ using System.Buffers; using System; using System.Numerics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; @@ -28,7 +29,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, - 2048)] + //512 + 256 + )] public int Count { get; set; } [GlobalSetup] @@ -45,7 +48,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark] + //[Benchmark] public void PerElement() { Span s = this.source.GetSpan(); @@ -53,32 +56,48 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk for (int i = 0; i < this.Count; i++) { - TPixel c = s[i]; - d[i] = c.ToVector4(); + d[i] = s[i].ToVector4(); } } - [Benchmark(Baseline = true)] + //[Benchmark] public void CommonBulk() { new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } - [Benchmark] + //[Benchmark] public void OptimizedBulk() { PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } - [CoreJob] - [ClrJob] + [RyuJitX64Job] + [DisassemblyDiagnoser(printAsm: true, printSource: true)] public class ToVector4_Rgba32 : ToVector4 { class Config : ManualConfig { } + [Benchmark(Baseline = true)] + public void FastScalarBulk() + { + ref Rgba32 sBase = ref this.source.GetSpan()[0]; + ref Vector4 dBase = ref this.destination.GetSpan()[0]; + + for (int i = 0; i < this.Count; i++) + { + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); + ref Vector4 d = ref Unsafe.Add(ref dBase, i); + d.X = s.R; + d.Y = s.G; + d.Z = s.B; + d.W = s.A; + } + } + [Benchmark] public void BulkConvertByteToNormalizedFloat() { @@ -97,5 +116,82 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } + //[Benchmark] + public void Original() + { + ToVector4SimdAligned(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ToVector4SimdAligned(ReadOnlySpan sourceColors, Span destVectors, int count) + { + if (!Vector.IsHardwareAccelerated) + { + throw new InvalidOperationException( + "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); + } + + DebugGuard.IsTrue( + count % Vector.Count == 0, + nameof(count), + "Argument 'count' should divisible by Vector.Count!"); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + int unpackedRawCount = count * 4; + + ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); + ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); + ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); + + for (int i = 0; i < count; i++) + { + uint sVal = Unsafe.Add(ref sourceBase, i); + ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i); + + // This call is the bottleneck now: + dst.Load(sVal); + } + + int numOfVectors = unpackedRawCount / Vector.Count; + + for (int i = 0; i < numOfVectors; i++) + { + Vector vi = Unsafe.Add(ref destBaseAsUInt, i); + + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + Unsafe.Add(ref destBaseAsFloat, i) = vf; + } + } + + [StructLayout(LayoutKind.Sequential)] + private struct UnpackedRGBA + { + private uint r; + + private uint g; + + private uint b; + + private uint a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Load(uint p) + { + this.r = p; + this.g = p >> 8; + this.b = p >> 16; + this.a = p >> 24; + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 535952e051..abf764881b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 1111 }; + public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 1111 }; private static PixelOperations Operations => PixelOperations.Instance; From 0e06eb635557d3e021d7afee3ee41c1f28a5575d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 19 Oct 2018 13:38:03 +0200 Subject: [PATCH 030/238] benchmark conversion steps separately --- .../General/Vectorization/UInt32ToSingle.cs | 66 +++++++++++++++++++ .../Vectorization/WidenBytesToUInt32.cs | 61 +++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs new file mode 100644 index 0000000000..4a4b939b65 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -0,0 +1,66 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ + public class UInt32ToSingle + { + private float[] data; + + private const int Count = 64; + + [GlobalSetup] + public void Setup() + { + this.data = new float[Count]; + } + + [Benchmark(Baseline = true)] + public void MagicMethod() + { + ref Vector b = ref Unsafe.As>(ref this.data[0]); + + int n = Count / Vector.Count; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + + ref Vector d = ref Unsafe.Add(ref b, i); + Vector x = d; + //x = Vector.Max(x, Vector.Zero); + //x = Vector.Min(x, Vector.One); + + x = (x * scale) + magick; + d = x; + } + } + + [Benchmark] + public void StandardSimd() + { + int n = Count / Vector.Count; + + ref Vector b = ref Unsafe.As>(ref this.data[0]); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref b, i); + Vector du = Unsafe.As, Vector>(ref df); + + Vector v = Vector.ConvertToSingle(du); + v *= scale; + df = v; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs new file mode 100644 index 0000000000..f71f6ec1bf --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs @@ -0,0 +1,61 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ + public class WidenBytesToUInt32 + { + private byte[] source; + + private uint[] dest; + + private const int Count = 64; + + [GlobalSetup] + public void Setup() + { + this.source = new byte[Count]; + this.dest = new uint[Count]; + } + + [Benchmark(Baseline = true)] + public void Standard() + { + const int N = Count / 8; + + ref SimdUtils.Octet.OfByte sBase = ref Unsafe.As(ref this.source[0]); + ref SimdUtils.Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < N; i++) + { + Unsafe.Add(ref dBase, i).LoadFrom(ref Unsafe.Add(ref sBase, i)); + } + } + + [Benchmark] + public void Simd() + { + int n = Count / Vector.Count; + + ref Vector sBase = ref Unsafe.As>(ref this.source[0]); + ref Vector dBase = ref Unsafe.As>(ref this.dest[0]); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref dBase, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + } + } +} \ No newline at end of file From 9370a6e5354f25687a6da4da83e29ddf835e7b85 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 19 Oct 2018 21:56:27 +0100 Subject: [PATCH 031/238] Add generic palette quantizer, refactor + werner palette --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 5 +- src/ImageSharp/PixelFormats/ColorConstants.cs | 409 +++++++++++------- .../PixelFormats/NamedColors{TPixel}.cs | 26 +- src/ImageSharp/Processing/KnownQuantizers.cs | 13 +- .../Quantization/OctreeQuantizer.cs | 13 +- .../PaletteFrameQuantizer{TPixel}.cs | 5 +- .../Quantization/PaletteQuantizer.cs | 50 +-- .../Quantization/PaletteQuantizer{TPixel}.cs | 92 ++++ .../Quantization/QuantizerConstants.cs | 21 + .../Quantization/WebSafePaletteQuantizer.cs | 47 ++ .../Quantization/WernerPaletteQuantizer.cs | 48 ++ .../Processors/Quantization/WuQuantizer.cs | 13 +- .../ImageSharp.Benchmarks/Codecs/EncodeGif.cs | 2 +- .../Codecs/EncodeGifMultiple.cs | 2 +- .../Codecs/EncodeIndexedPng.cs | 4 +- .../Formats/GeneralFormatTests.cs | 3 +- .../Formats/Gif/GifEncoderTests.cs | 2 +- .../Quantization/QuantizedImageTests.cs | 11 +- 18 files changed, 545 insertions(+), 221 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs create mode 100644 src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs create mode 100644 src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs create mode 100644 src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ae0366e6e6..a8cd169e5d 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private void EncodeGlobal(Image image, QuantizedFrame quantized, int transparencyIndex, Stream stream) where TPixel : struct, IPixel { - var palleteQuantizer = new PaletteQuantizer(this.quantizer.Diffuser); + var palleteQuantizer = new PaletteQuantizer(quantized.Palette, this.quantizer.Diffuser); for (int i = 0; i < image.Frames.Count; i++) { @@ -149,8 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - using (QuantizedFrame paletteQuantized - = palleteQuantizer.CreateFrameQuantizer(() => quantized.Palette).QuantizeFrame(frame)) + using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer().QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } diff --git a/src/ImageSharp/PixelFormats/ColorConstants.cs b/src/ImageSharp/PixelFormats/ColorConstants.cs index bac05c53d2..14df385697 100644 --- a/src/ImageSharp/PixelFormats/ColorConstants.cs +++ b/src/ImageSharp/PixelFormats/ColorConstants.cs @@ -11,157 +11,268 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Gets a collection of named, web safe, colors as defined in the CSS Color Module Level 4. /// - public static readonly Rgba32[] WebSafeColors = GetWebSafeColors(); + public static readonly Rgba32[] WebSafeColors = + { + Rgba32.AliceBlue, + Rgba32.AntiqueWhite, + Rgba32.Aqua, + Rgba32.Aquamarine, + Rgba32.Azure, + Rgba32.Beige, + Rgba32.Bisque, + Rgba32.Black, + Rgba32.BlanchedAlmond, + Rgba32.Blue, + Rgba32.BlueViolet, + Rgba32.Brown, + Rgba32.BurlyWood, + Rgba32.CadetBlue, + Rgba32.Chartreuse, + Rgba32.Chocolate, + Rgba32.Coral, + Rgba32.CornflowerBlue, + Rgba32.Cornsilk, + Rgba32.Crimson, + Rgba32.Cyan, + Rgba32.DarkBlue, + Rgba32.DarkCyan, + Rgba32.DarkGoldenrod, + Rgba32.DarkGray, + Rgba32.DarkGreen, + Rgba32.DarkKhaki, + Rgba32.DarkMagenta, + Rgba32.DarkOliveGreen, + Rgba32.DarkOrange, + Rgba32.DarkOrchid, + Rgba32.DarkRed, + Rgba32.DarkSalmon, + Rgba32.DarkSeaGreen, + Rgba32.DarkSlateBlue, + Rgba32.DarkSlateGray, + Rgba32.DarkTurquoise, + Rgba32.DarkViolet, + Rgba32.DeepPink, + Rgba32.DeepSkyBlue, + Rgba32.DimGray, + Rgba32.DodgerBlue, + Rgba32.Firebrick, + Rgba32.FloralWhite, + Rgba32.ForestGreen, + Rgba32.Fuchsia, + Rgba32.Gainsboro, + Rgba32.GhostWhite, + Rgba32.Gold, + Rgba32.Goldenrod, + Rgba32.Gray, + Rgba32.Green, + Rgba32.GreenYellow, + Rgba32.Honeydew, + Rgba32.HotPink, + Rgba32.IndianRed, + Rgba32.Indigo, + Rgba32.Ivory, + Rgba32.Khaki, + Rgba32.Lavender, + Rgba32.LavenderBlush, + Rgba32.LawnGreen, + Rgba32.LemonChiffon, + Rgba32.LightBlue, + Rgba32.LightCoral, + Rgba32.LightCyan, + Rgba32.LightGoldenrodYellow, + Rgba32.LightGray, + Rgba32.LightGreen, + Rgba32.LightPink, + Rgba32.LightSalmon, + Rgba32.LightSeaGreen, + Rgba32.LightSkyBlue, + Rgba32.LightSlateGray, + Rgba32.LightSteelBlue, + Rgba32.LightYellow, + Rgba32.Lime, + Rgba32.LimeGreen, + Rgba32.Linen, + Rgba32.Magenta, + Rgba32.Maroon, + Rgba32.MediumAquamarine, + Rgba32.MediumBlue, + Rgba32.MediumOrchid, + Rgba32.MediumPurple, + Rgba32.MediumSeaGreen, + Rgba32.MediumSlateBlue, + Rgba32.MediumSpringGreen, + Rgba32.MediumTurquoise, + Rgba32.MediumVioletRed, + Rgba32.MidnightBlue, + Rgba32.MintCream, + Rgba32.MistyRose, + Rgba32.Moccasin, + Rgba32.NavajoWhite, + Rgba32.Navy, + Rgba32.OldLace, + Rgba32.Olive, + Rgba32.OliveDrab, + Rgba32.Orange, + Rgba32.OrangeRed, + Rgba32.Orchid, + Rgba32.PaleGoldenrod, + Rgba32.PaleGreen, + Rgba32.PaleTurquoise, + Rgba32.PaleVioletRed, + Rgba32.PapayaWhip, + Rgba32.PeachPuff, + Rgba32.Peru, + Rgba32.Pink, + Rgba32.Plum, + Rgba32.PowderBlue, + Rgba32.Purple, + Rgba32.RebeccaPurple, + Rgba32.Red, + Rgba32.RosyBrown, + Rgba32.RoyalBlue, + Rgba32.SaddleBrown, + Rgba32.Salmon, + Rgba32.SandyBrown, + Rgba32.SeaGreen, + Rgba32.SeaShell, + Rgba32.Sienna, + Rgba32.Silver, + Rgba32.SkyBlue, + Rgba32.SlateBlue, + Rgba32.SlateGray, + Rgba32.Snow, + Rgba32.SpringGreen, + Rgba32.SteelBlue, + Rgba32.Tan, + Rgba32.Teal, + Rgba32.Thistle, + Rgba32.Tomato, + Rgba32.Transparent, + Rgba32.Turquoise, + Rgba32.Violet, + Rgba32.Wheat, + Rgba32.White, + Rgba32.WhiteSmoke, + Rgba32.Yellow, + Rgba32.YellowGreen + }; /// - /// Returns an array of web safe colors. + /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux /// - /// The - private static Rgba32[] GetWebSafeColors() - => new Rgba32[] - { - Rgba32.AliceBlue, - Rgba32.AntiqueWhite, - Rgba32.Aqua, - Rgba32.Aquamarine, - Rgba32.Azure, - Rgba32.Beige, - Rgba32.Bisque, - Rgba32.Black, - Rgba32.BlanchedAlmond, - Rgba32.Blue, - Rgba32.BlueViolet, - Rgba32.Brown, - Rgba32.BurlyWood, - Rgba32.CadetBlue, - Rgba32.Chartreuse, - Rgba32.Chocolate, - Rgba32.Coral, - Rgba32.CornflowerBlue, - Rgba32.Cornsilk, - Rgba32.Crimson, - Rgba32.Cyan, - Rgba32.DarkBlue, - Rgba32.DarkCyan, - Rgba32.DarkGoldenrod, - Rgba32.DarkGray, - Rgba32.DarkGreen, - Rgba32.DarkKhaki, - Rgba32.DarkMagenta, - Rgba32.DarkOliveGreen, - Rgba32.DarkOrange, - Rgba32.DarkOrchid, - Rgba32.DarkRed, - Rgba32.DarkSalmon, - Rgba32.DarkSeaGreen, - Rgba32.DarkSlateBlue, - Rgba32.DarkSlateGray, - Rgba32.DarkTurquoise, - Rgba32.DarkViolet, - Rgba32.DeepPink, - Rgba32.DeepSkyBlue, - Rgba32.DimGray, - Rgba32.DodgerBlue, - Rgba32.Firebrick, - Rgba32.FloralWhite, - Rgba32.ForestGreen, - Rgba32.Fuchsia, - Rgba32.Gainsboro, - Rgba32.GhostWhite, - Rgba32.Gold, - Rgba32.Goldenrod, - Rgba32.Gray, - Rgba32.Green, - Rgba32.GreenYellow, - Rgba32.Honeydew, - Rgba32.HotPink, - Rgba32.IndianRed, - Rgba32.Indigo, - Rgba32.Ivory, - Rgba32.Khaki, - Rgba32.Lavender, - Rgba32.LavenderBlush, - Rgba32.LawnGreen, - Rgba32.LemonChiffon, - Rgba32.LightBlue, - Rgba32.LightCoral, - Rgba32.LightCyan, - Rgba32.LightGoldenrodYellow, - Rgba32.LightGray, - Rgba32.LightGreen, - Rgba32.LightPink, - Rgba32.LightSalmon, - Rgba32.LightSeaGreen, - Rgba32.LightSkyBlue, - Rgba32.LightSlateGray, - Rgba32.LightSteelBlue, - Rgba32.LightYellow, - Rgba32.Lime, - Rgba32.LimeGreen, - Rgba32.Linen, - Rgba32.Magenta, - Rgba32.Maroon, - Rgba32.MediumAquamarine, - Rgba32.MediumBlue, - Rgba32.MediumOrchid, - Rgba32.MediumPurple, - Rgba32.MediumSeaGreen, - Rgba32.MediumSlateBlue, - Rgba32.MediumSpringGreen, - Rgba32.MediumTurquoise, - Rgba32.MediumVioletRed, - Rgba32.MidnightBlue, - Rgba32.MintCream, - Rgba32.MistyRose, - Rgba32.Moccasin, - Rgba32.NavajoWhite, - Rgba32.Navy, - Rgba32.OldLace, - Rgba32.Olive, - Rgba32.OliveDrab, - Rgba32.Orange, - Rgba32.OrangeRed, - Rgba32.Orchid, - Rgba32.PaleGoldenrod, - Rgba32.PaleGreen, - Rgba32.PaleTurquoise, - Rgba32.PaleVioletRed, - Rgba32.PapayaWhip, - Rgba32.PeachPuff, - Rgba32.Peru, - Rgba32.Pink, - Rgba32.Plum, - Rgba32.PowderBlue, - Rgba32.Purple, - Rgba32.RebeccaPurple, - Rgba32.Red, - Rgba32.RosyBrown, - Rgba32.RoyalBlue, - Rgba32.SaddleBrown, - Rgba32.Salmon, - Rgba32.SandyBrown, - Rgba32.SeaGreen, - Rgba32.SeaShell, - Rgba32.Sienna, - Rgba32.Silver, - Rgba32.SkyBlue, - Rgba32.SlateBlue, - Rgba32.SlateGray, - Rgba32.Snow, - Rgba32.SpringGreen, - Rgba32.SteelBlue, - Rgba32.Tan, - Rgba32.Teal, - Rgba32.Thistle, - Rgba32.Tomato, - Rgba32.Transparent, - Rgba32.Turquoise, - Rgba32.Violet, - Rgba32.Wheat, - Rgba32.White, - Rgba32.WhiteSmoke, - Rgba32.Yellow, - Rgba32.YellowGreen - }; + public static readonly Rgba32[] WernerColors = + { + Rgba32.FromHex("#f1e9cd"), + Rgba32.FromHex("#f2e7cf"), + Rgba32.FromHex("#ece6d0"), + Rgba32.FromHex("#f2eacc"), + Rgba32.FromHex("#f3e9ca"), + Rgba32.FromHex("#f2ebcd"), + Rgba32.FromHex("#e6e1c9"), + Rgba32.FromHex("#e2ddc6"), + Rgba32.FromHex("#cbc8b7"), + Rgba32.FromHex("#bfbbb0"), + Rgba32.FromHex("#bebeb3"), + Rgba32.FromHex("#b7b5ac"), + Rgba32.FromHex("#bab191"), + Rgba32.FromHex("#9c9d9a"), + Rgba32.FromHex("#8a8d84"), + Rgba32.FromHex("#5b5c61"), + Rgba32.FromHex("#555152"), + Rgba32.FromHex("#413f44"), + Rgba32.FromHex("#454445"), + Rgba32.FromHex("#423937"), + Rgba32.FromHex("#433635"), + Rgba32.FromHex("#252024"), + Rgba32.FromHex("#241f20"), + Rgba32.FromHex("#281f3f"), + Rgba32.FromHex("#1c1949"), + Rgba32.FromHex("#4f638d"), + Rgba32.FromHex("#383867"), + Rgba32.FromHex("#5c6b8f"), + Rgba32.FromHex("#657abb"), + Rgba32.FromHex("#6f88af"), + Rgba32.FromHex("#7994b5"), + Rgba32.FromHex("#6fb5a8"), + Rgba32.FromHex("#719ba2"), + Rgba32.FromHex("#8aa1a6"), + Rgba32.FromHex("#d0d5d3"), + Rgba32.FromHex("#8590ae"), + Rgba32.FromHex("#3a2f52"), + Rgba32.FromHex("#39334a"), + Rgba32.FromHex("#6c6d94"), + Rgba32.FromHex("#584c77"), + Rgba32.FromHex("#533552"), + Rgba32.FromHex("#463759"), + Rgba32.FromHex("#bfbac0"), + Rgba32.FromHex("#77747f"), + Rgba32.FromHex("#4a475c"), + Rgba32.FromHex("#b8bfaf"), + Rgba32.FromHex("#b2b599"), + Rgba32.FromHex("#979c84"), + Rgba32.FromHex("#5d6161"), + Rgba32.FromHex("#61ac86"), + Rgba32.FromHex("#a4b6a7"), + Rgba32.FromHex("#adba98"), + Rgba32.FromHex("#93b778"), + Rgba32.FromHex("#7d8c55"), + Rgba32.FromHex("#33431e"), + Rgba32.FromHex("#7c8635"), + Rgba32.FromHex("#8e9849"), + Rgba32.FromHex("#c2c190"), + Rgba32.FromHex("#67765b"), + Rgba32.FromHex("#ab924b"), + Rgba32.FromHex("#c8c76f"), + Rgba32.FromHex("#ccc050"), + Rgba32.FromHex("#ebdd99"), + Rgba32.FromHex("#ab9649"), + Rgba32.FromHex("#dbc364"), + Rgba32.FromHex("#e6d058"), + Rgba32.FromHex("#ead665"), + Rgba32.FromHex("#d09b2c"), + Rgba32.FromHex("#a36629"), + Rgba32.FromHex("#a77d35"), + Rgba32.FromHex("#f0d696"), + Rgba32.FromHex("#d7c485"), + Rgba32.FromHex("#f1d28c"), + Rgba32.FromHex("#efcc83"), + Rgba32.FromHex("#f3daa7"), + Rgba32.FromHex("#dfa837"), + Rgba32.FromHex("#ebbc71"), + Rgba32.FromHex("#d17c3f"), + Rgba32.FromHex("#92462f"), + Rgba32.FromHex("#be7249"), + Rgba32.FromHex("#bb603c"), + Rgba32.FromHex("#c76b4a"), + Rgba32.FromHex("#a75536"), + Rgba32.FromHex("#b63e36"), + Rgba32.FromHex("#b5493a"), + Rgba32.FromHex("#cd6d57"), + Rgba32.FromHex("#711518"), + Rgba32.FromHex("#e9c49d"), + Rgba32.FromHex("#eedac3"), + Rgba32.FromHex("#eecfbf"), + Rgba32.FromHex("#ce536b"), + Rgba32.FromHex("#b74a70"), + Rgba32.FromHex("#b7757c"), + Rgba32.FromHex("#612741"), + Rgba32.FromHex("#7a4848"), + Rgba32.FromHex("#3f3033"), + Rgba32.FromHex("#8d746f"), + Rgba32.FromHex("#4d3635"), + Rgba32.FromHex("#6e3b31"), + Rgba32.FromHex("#864735"), + Rgba32.FromHex("#553d3a"), + Rgba32.FromHex("#613936"), + Rgba32.FromHex("#7a4b3a"), + Rgba32.FromHex("#946943"), + Rgba32.FromHex("#c39e6d"), + Rgba32.FromHex("#513e32"), + Rgba32.FromHex("#8b7859"), + Rgba32.FromHex("#9b856b"), + Rgba32.FromHex("#766051"), + Rgba32.FromHex("#453b32") + }; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 0f42e182c5..a0916b1636 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -14,9 +14,10 @@ namespace SixLabors.ImageSharp.PixelFormats where TPixel : struct, IPixel { /// - /// Thread-safe backing field for . + /// Thread-safe backing field for the constant palettes. /// private static readonly Lazy WebSafePaletteLazy = new Lazy(GetWebSafePalette, true); + private static readonly Lazy WernerPaletteLazy = new Lazy(GetWernerPalette, true); /// /// Represents a matching the W3C definition that has an hex value of #F0F8FF. @@ -729,18 +730,27 @@ namespace SixLabors.ImageSharp.PixelFormats public static readonly TPixel YellowGreen = ColorBuilder.FromRGBA(154, 205, 50, 255); /// - /// Gets a matching the W3C definition of web safe colors. + /// Gets a collection of web safe, colors as defined in the CSS Color Module Level 4. /// public static TPixel[] WebSafePalette => WebSafePaletteLazy.Value; - private static TPixel[] GetWebSafePalette() + /// + /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// + public static TPixel[] WernerPalette => WernerPaletteLazy.Value; + + private static TPixel[] GetWebSafePalette() => GetPalette(ColorConstants.WebSafeColors); + + private static TPixel[] GetWernerPalette() => GetPalette(ColorConstants.WernerColors); + + private static TPixel[] GetPalette(Rgba32[] palette) { - Rgba32[] constants = ColorConstants.WebSafeColors; - var safe = new TPixel[constants.Length + 1]; + var converted = new TPixel[palette.Length + 1]; - Span constantsBytes = MemoryMarshal.Cast(constants.AsSpan()); - PixelOperations.Instance.PackFromRgba32Bytes(constantsBytes, safe, constants.Length); - return safe; + Span constantsBytes = MemoryMarshal.Cast(palette.AsSpan()); + PixelOperations.Instance.PackFromRgba32Bytes(constantsBytes, converted, palette.Length); + return converted; } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/KnownQuantizers.cs b/src/ImageSharp/Processing/KnownQuantizers.cs index fe98063104..e93a9921a9 100644 --- a/src/ImageSharp/Processing/KnownQuantizers.cs +++ b/src/ImageSharp/Processing/KnownQuantizers.cs @@ -23,9 +23,16 @@ namespace SixLabors.ImageSharp.Processing public static IQuantizer Wu { get; } = new WuQuantizer(); /// - /// Gets the palette based, Using the collection of web-safe colors. - /// The quantizer supports multiple alpha values. + /// Gets the palette based quantizer consisting of web safe colors as defined in the CSS Color Module Level 4. + /// The quantizer supports a single alpha value. + /// + public static IQuantizer WebSafe { get; } = new WebSafePaletteQuantizer(); + + /// + /// Gets the palette based quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// The quantizer supports a single alpha value. /// - public static IQuantizer Palette { get; } = new PaletteQuantizer(); + public static IQuantizer Werner { get; } = new WernerPaletteQuantizer(); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 22bb5223f0..d0dd18393e 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -15,11 +15,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class OctreeQuantizer : IQuantizer { - /// - /// The default maximum number of colors to use when quantizing the image. - /// - public const int DefaultMaxColors = 256; - /// /// Initializes a new instance of the class. /// @@ -42,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Whether to apply dithering to the output image public OctreeQuantizer(bool dither) - : this(GetDiffuser(dither), DefaultMaxColors) + : this(GetDiffuser(dither), QuantizerConstants.MaxColors) { } @@ -51,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The error diffusion algorithm, if any, to apply to the output image public OctreeQuantizer(IErrorDiffuser diffuser) - : this(diffuser, DefaultMaxColors) + : this(diffuser, QuantizerConstants.MaxColors) { } @@ -63,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public OctreeQuantizer(IErrorDiffuser diffuser, int maxColors) { this.Diffuser = diffuser; - this.MaxColors = maxColors.Clamp(1, DefaultMaxColors); + this.MaxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); } /// @@ -83,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public IFrameQuantizer CreateFrameQuantizer(int maxColors) where TPixel : struct, IPixel { - maxColors = maxColors.Clamp(1, DefaultMaxColors); + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); return new OctreeFrameQuantizer(this, maxColors); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index cdf3514e2d..10f46e68ac 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -33,12 +33,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The palette quantizer. /// An array of all colors in the palette. - public PaletteFrameQuantizer(PaletteQuantizer quantizer, TPixel[] colors) + public PaletteFrameQuantizer(IQuantizer quantizer, TPixel[] colors) : base(quantizer, true) { - // TODO: Why is this value constrained? Gif has limitations but theoretically - // we might want to reduce the palette of an image to greater than that limitation. - Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors)); this.palette = colors; this.paletteVector = new Vector4[this.palette.Length]; PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector, this.palette.Length); diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 27ef05dfe9..5dace6b179 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -8,18 +8,18 @@ using SixLabors.ImageSharp.Processing.Processors.Dithering; namespace SixLabors.ImageSharp.Processing.Processors.Quantization { /// - /// Allows the quantization of images pixels using web safe colors defined in the CSS Color Module Level 4. - /// Override this class to provide your own palette. + /// Allows the quantization of images pixels using color palettes. + /// Override this class to provide your own palette. /// - /// By default the quantizer uses dithering and the + /// By default the quantizer uses dithering. /// /// - public class PaletteQuantizer : IQuantizer + public abstract class PaletteQuantizer : IQuantizer { /// /// Initializes a new instance of the class. /// - public PaletteQuantizer() + protected PaletteQuantizer() : this(true) { } @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Initializes a new instance of the class. /// /// Whether to apply dithering to the output image - public PaletteQuantizer(bool dither) + protected PaletteQuantizer(bool dither) : this(GetDiffuser(dither)) { } @@ -37,41 +37,39 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Initializes a new instance of the class. /// /// The error diffusion algorithm, if any, to apply to the output image - public PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser; + protected PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser; /// public IErrorDiffuser Diffuser { get; } /// - public virtual IFrameQuantizer CreateFrameQuantizer() - where TPixel : struct, IPixel - => this.CreateFrameQuantizer(() => NamedColors.WebSafePalette); + public abstract IFrameQuantizer CreateFrameQuantizer() + where TPixel : struct, IPixel; /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public abstract IFrameQuantizer CreateFrameQuantizer(int maxColors) + where TPixel : struct, IPixel; + + /// + /// Creates the generic frame quantizer. + /// + /// The pixel format. + /// The color palette. + /// The maximum number of colors to hold in the color palette. + /// The + protected IFrameQuantizer CreateFrameQuantizer(TPixel[] palette, int maxColors) where TPixel : struct, IPixel { - TPixel[] websafe = NamedColors.WebSafePalette; - int max = Math.Min(maxColors, websafe.Length); + int max = Math.Min(QuantizerConstants.MaxColors, Math.Min(maxColors, palette.Length)); - if (max != websafe.Length) + if (max != palette.Length) { - return this.CreateFrameQuantizer(() => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); + return new PaletteFrameQuantizer(this, palette.AsSpan(0, max).ToArray()); } - return this.CreateFrameQuantizer(() => websafe); + return new PaletteFrameQuantizer(this, palette); } - /// - /// Gets the palette to use to quantize the image. - /// - /// The pixel format. - /// The method to return the palette. - /// The - public IFrameQuantizer CreateFrameQuantizer(Func paletteFunction) - where TPixel : struct, IPixel - => new PaletteFrameQuantizer(this, paletteFunction.Invoke()); - private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs new file mode 100644 index 0000000000..02ffc76ef0 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -0,0 +1,92 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A generic palette quantizer. + /// + /// The pixel format. + public class PaletteQuantizer : IQuantizer + where TPixel : struct, IPixel + { + private readonly TPixel[] palette; + + /// + /// Initializes a new instance of the class. + /// + /// The color palette to use. + public PaletteQuantizer(TPixel[] palette) + : this(palette, true) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The color palette to use. + /// Whether to apply dithering to the output image + public PaletteQuantizer(TPixel[] palette, bool dither) + : this(palette, GetDiffuser(dither)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The color palette to use. + /// The error diffusion algorithm, if any, to apply to the output image + public PaletteQuantizer(TPixel[] palette, IErrorDiffuser diffuser) + { + Guard.MustBeBetweenOrEqualTo(palette.Length, QuantizerConstants.MinColors, QuantizerConstants.MaxColors, nameof(palette)); + this.palette = palette; + this.Diffuser = diffuser; + } + + /// + public IErrorDiffuser Diffuser { get; } + + /// + public IFrameQuantizer CreateFrameQuantizer() + where TPixel1 : struct, IPixel + { + if (!typeof(TPixel).Equals(typeof(TPixel1))) + { + throw new InvalidOperationException("Generic method type must be the same as class type."); + } + + TPixel[] paletteRef = this.palette; + return new PaletteFrameQuantizer(this, Unsafe.As(ref paletteRef)); + } + + /// + public IFrameQuantizer CreateFrameQuantizer(int maxColors) + where TPixel1 : struct, IPixel + { + if (!typeof(TPixel).Equals(typeof(TPixel1))) + { + throw new InvalidOperationException("Generic method type must be the same as class type."); + } + + TPixel[] paletteRef = this.palette; + TPixel1[] castPalette = Unsafe.As(ref paletteRef); + + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); + int max = Math.Min(maxColors, castPalette.Length); + + if (max != castPalette.Length) + { + return new PaletteFrameQuantizer(this, castPalette.AsSpan(0, max).ToArray()); + } + + return new PaletteFrameQuantizer(this, castPalette); + } + + private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs new file mode 100644 index 0000000000..d79a91c301 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// Contains color quantization specific constants. + /// + internal static class QuantizerConstants + { + /// + /// The minimum number of colors to use when quantizing an image. + /// + public const int MinColors = 1; + + /// + /// The maximum number of colors to use when quantizing an image. + /// + public const int MaxColors = 256; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs new file mode 100644 index 0000000000..bfa368a2e5 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs @@ -0,0 +1,47 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A palette quantizer consisting of web safe colors as defined in the CSS Color Module Level 4. + /// + public class WebSafePaletteQuantizer : PaletteQuantizer + { + /// + /// Initializes a new instance of the class. + /// + public WebSafePaletteQuantizer() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Whether to apply dithering to the output image + public WebSafePaletteQuantizer(bool dither) + : base(dither) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The error diffusion algorithm, if any, to apply to the output image + public WebSafePaletteQuantizer(IErrorDiffuser diffuser) + : base(diffuser) + { + } + + /// + public override IFrameQuantizer CreateFrameQuantizer() + => this.CreateFrameQuantizer(NamedColors.WebSafePalette.Length); + + /// + public override IFrameQuantizer CreateFrameQuantizer(int maxColors) + => this.CreateFrameQuantizer(NamedColors.WebSafePalette, maxColors); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs new file mode 100644 index 0000000000..9a91a63d3d --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A palette quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// + public class WernerPaletteQuantizer : PaletteQuantizer + { + /// + /// Initializes a new instance of the class. + /// + public WernerPaletteQuantizer() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Whether to apply dithering to the output image + public WernerPaletteQuantizer(bool dither) + : base(dither) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The error diffusion algorithm, if any, to apply to the output image + public WernerPaletteQuantizer(IErrorDiffuser diffuser) + : base(diffuser) + { + } + + /// + public override IFrameQuantizer CreateFrameQuantizer() + => this.CreateFrameQuantizer(NamedColors.WernerPalette.Length); + + /// + public override IFrameQuantizer CreateFrameQuantizer(int maxColors) + => this.CreateFrameQuantizer(NamedColors.WernerPalette, maxColors); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 5123e737d3..629f7a2385 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -14,11 +14,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class WuQuantizer : IQuantizer { - /// - /// The default maximum number of colors to use when quantizing the image. - /// - public const int DefaultMaxColors = 256; - /// /// Initializes a new instance of the class. /// @@ -41,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Whether to apply dithering to the output image public WuQuantizer(bool dither) - : this(GetDiffuser(dither), DefaultMaxColors) + : this(GetDiffuser(dither), QuantizerConstants.MaxColors) { } @@ -50,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The error diffusion algorithm, if any, to apply to the output image public WuQuantizer(IErrorDiffuser diffuser) - : this(diffuser, DefaultMaxColors) + : this(diffuser, QuantizerConstants.MaxColors) { } @@ -62,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public WuQuantizer(IErrorDiffuser diffuser, int maxColors) { this.Diffuser = diffuser; - this.MaxColors = maxColors.Clamp(1, DefaultMaxColors); + this.MaxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); } /// @@ -82,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public IFrameQuantizer CreateFrameQuantizer(int maxColors) where TPixel : struct, IPixel { - maxColors = maxColors.Clamp(1, DefaultMaxColors); + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); return new WuFrameQuantizer(this, maxColors); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs index 12e74ccdbb..89eb63d629 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public void GifCore() { // Try to get as close to System.Drawing's output as possible - var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) }; + var options = new GifEncoder { Quantizer = new WebSafePaletteQuantizer(false) }; using (var memoryStream = new MemoryStream()) { this.bmpCore.SaveAsGif(memoryStream, options); diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs index 9b94347f34..bf9627f4c1 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs this.ForEachImageSharpImage((img, ms) => { // Try to get as close to System.Drawing's output as possible - var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) }; + var options = new GifEncoder { Quantizer = new WebSafePaletteQuantizer(false) }; img.Save(ms, options); return null; }); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs index 962b34eb7c..639d1594ee 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs { using (var memoryStream = new MemoryStream()) { - var options = new PngEncoder { Quantizer = KnownQuantizers.Palette }; + var options = new PngEncoder { Quantizer = KnownQuantizers.WebSafe }; this.bmpCore.SaveAsPng(memoryStream, options); } } @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs { using (var memoryStream = new MemoryStream()) { - var options = new PngEncoder { Quantizer = new PaletteQuantizer(false) }; + var options = new PngEncoder { Quantizer = new WebSafePaletteQuantizer(false) }; this.bmpCore.SaveAsPng(memoryStream, options); } } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 1d21c65fda..158a085d5a 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -67,7 +67,8 @@ namespace SixLabors.ImageSharp.Tests new TheoryData { nameof(KnownQuantizers.Octree), - nameof(KnownQuantizers.Palette), + nameof(KnownQuantizers.WebSafe), + nameof(KnownQuantizers.Werner), nameof(KnownQuantizers.Wu) }; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index c5c971962c..a98ae164a1 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif { // Use the palette quantizer without dithering to ensure results // are consistant - Quantizer = new PaletteQuantizer(false) + Quantizer = new WebSafePaletteQuantizer(false) }; // Always save as we need to compare the encoded output. diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index c2b1c26c54..fb32522c9c 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -13,15 +13,18 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void QuantizersDitherByDefault() { - var palette = new PaletteQuantizer(); + var werner = new WernerPaletteQuantizer(); + var websafe = new WebSafePaletteQuantizer(); var octree = new OctreeQuantizer(); var wu = new WuQuantizer(); - Assert.NotNull(palette.Diffuser); + Assert.NotNull(werner.Diffuser); + Assert.NotNull(websafe.Diffuser); Assert.NotNull(octree.Diffuser); Assert.NotNull(wu.Diffuser); - Assert.True(palette.CreateFrameQuantizer().Dither); + Assert.True(werner.CreateFrameQuantizer().Dither); + Assert.True(websafe.CreateFrameQuantizer().Dither); Assert.True(octree.CreateFrameQuantizer().Dither); Assert.True(wu.CreateFrameQuantizer().Dither); } @@ -36,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests { Assert.True(image[0, 0].Equals(default(TPixel))); - var quantizer = new PaletteQuantizer(dither); + var quantizer = new WebSafePaletteQuantizer(dither); foreach (ImageFrame frame in image.Frames) { From 0f538ff1953b637d01f6c913b068cad763cd9152 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 14:42:23 +0200 Subject: [PATCH 032/238] fixed benchmarks and optimized implementation --- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 61 +++--- .../Color/Bulk/PackFromVector4.cs | 67 +++--- .../Color/Bulk/ToVector4.cs | 197 +++++++++++++++--- .../General/Vectorization/UInt32ToSingle.cs | 52 +++-- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 6 +- 5 files changed, 279 insertions(+), 104 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 6def8938a9..3131f18738 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -39,9 +39,8 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); - const float Scale = 1f / 255f; + var scale = new Vector(1f / 255f); for (int i = 0; i < n; i++) { @@ -51,26 +50,28 @@ namespace SixLabors.ImageSharp Vector.Widen(s0, out Vector w0, out Vector w1); Vector.Widen(s1, out Vector w2, out Vector w3); - ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); - d = w0; - Unsafe.Add(ref d, 1) = w1; - Unsafe.Add(ref d, 2) = w2; - Unsafe.Add(ref d, 3) = w3; - } - - n = dest.Length / Vector.Count; + Vector f0 = ConvertToSingle(w0, scale); + Vector f1 = ConvertToSingle(w1, scale); + Vector f2 = ConvertToSingle(w2, scale); + Vector f3 = ConvertToSingle(w3, scale); - for (int i = 0; i < n; i++) - { - ref Vector df = ref Unsafe.Add(ref destBase, i); - ref Vector du = ref Unsafe.As, Vector>(ref df); - - Vector v = Vector.ConvertToSingle(du); - v *= Scale; - df = v; + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; + } + /// /// A variant of , which is faster on new .NET runtime. /// @@ -92,26 +93,21 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + Vector scale = new Vector(255); + for (int i = 0; i < n; i++) { ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); Vector f0 = s; - f0 = Clamp(f0); - Vector f1 = Unsafe.Add(ref s, 1); - f1 = Clamp(f1); - Vector f2 = Unsafe.Add(ref s, 2); - f2 = Clamp(f2); - Vector f3 = Unsafe.Add(ref s, 3); - f3 = Clamp(f3); - Vector w0 = Vector.ConvertToUInt32(f0 * 255f); - Vector w1 = Vector.ConvertToUInt32(f1 * 255f); - Vector w2 = Vector.ConvertToUInt32(f2 * 255f); - Vector w3 = Vector.ConvertToUInt32(f3 * 255f); + Vector w0 = ConvertToUInt32(f0, scale); + Vector w1 = ConvertToUInt32(f1, scale); + Vector w2 = ConvertToUInt32(f2, scale); + Vector w3 = ConvertToUInt32(f3, scale); Vector u0 = Vector.Narrow(w0, w1); Vector u1 = Vector.Narrow(w2, w3); @@ -123,9 +119,12 @@ namespace SixLabors.ImageSharp } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector Clamp(Vector x) + private static Vector ConvertToUInt32(Vector vf, Vector scale) { - return Vector.Min(Vector.Max(x, Vector.Zero), Vector.One); + vf = Vector.Min(Vector.Max(vf, Vector.Zero), Vector.One); + vf *= scale; + Vector vi = Vector.ConvertToInt32(vf); + return Vector.AsVectorUInt32(vi); } } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index fb505ddcbd..1153d8f401 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -26,7 +26,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, - 2048)] + 2048 + )] public int Count { get; set; } [GlobalSetup] @@ -43,7 +44,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.Dispose(); } - [Benchmark] + //[Benchmark] public void PerElement() { ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan()); @@ -55,14 +56,14 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark(Baseline = true)] - public void CommonBulk() + [Benchmark] + public void PixelOperations_Base() { new PixelOperations().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] - public void OptimizedBulk() + public void PixelOperations_Specialized() { PixelOperations.Instance.PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } @@ -70,7 +71,30 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class PackFromVector4_Rgba32 : PackFromVector4 { - //[Benchmark] + [Benchmark] + public void FastDefault() + { + ref Vector4 sBase = ref this.source.GetSpan()[0]; + ref Rgba32 dBase = ref this.destination.GetSpan()[0]; + + Vector4 maxBytes = new Vector4(255); + Vector4 half = new Vector4(0.5f); + + for (int i = 0; i < this.Count; i++) + { + Vector4 v = Unsafe.Add(ref sBase, i); + v *= maxBytes; + v += half; + v = Vector4.Clamp(v, Vector4.Zero, maxBytes); + ref Rgba32 d = ref Unsafe.Add(ref dBase, i); + d.R = (byte)v.X; + d.G = (byte)v.Y; + d.B = (byte)v.Z; + d.A = (byte)v.W; + } + } + + [Benchmark(Baseline = true)] public void BulkConvertNormalizedFloatToByteClampOverflows() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -88,29 +112,16 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } - // TODO: Check again later! // RESULTS: - // - // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 - // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores - // Frequency=2742187 Hz, Resolution=364.6724 ns, Timer=TSC - // .NET Core SDK=2.1.400-preview-009063 - // [Host] : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT - // Job-XIFINS : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 - // Job-RTQZPN : .NET Core 2.1.1 (CoreCLR 4.6.26606.02, CoreFX 4.6.26606.05), 64bit RyuJIT - // - // LaunchCount=1 TargetCount=3 WarmupCount=3 + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------------------------------- |-------- |------ |----------:|----------:|----------:|-------:|---------:|----------:| + // FastDefault | Clr | 2048 | 15.989 us | 6.1384 us | 0.3468 us | 4.07 | 0.08 | 0 B | + // BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3.931 us | 0.6264 us | 0.0354 us | 1.00 | 0.00 | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 2.100 us | 0.4717 us | 0.0267 us | 0.53 | 0.01 | 0 B | // - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | - // ----------------------------------------------------------------- |-------- |------ |----------:|-----------:|----------:|-------:|---------:|----------:| - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3.755 us | 0.8959 us | 0.0506 us | 0.22 | 0.00 | 0 B | - // PerElement | Clr | 2048 | 17.387 us | 15.1569 us | 0.8564 us | 1.02 | 0.04 | 0 B | - // CommonBulk | Clr | 2048 | 17.121 us | 0.7634 us | 0.0431 us | 1.00 | 0.00 | 24 B | - // OptimizedBulk | Clr | 2048 | 4.018 us | 0.3858 us | 0.0218 us | 0.23 | 0.00 | 0 B | - // | | | | | | | | | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 22.232 us | 1.6154 us | 0.0913 us | 1.31 | 0.04 | 0 B | - // PerElement | Core | 2048 | 16.741 us | 2.9254 us | 0.1653 us | 0.98 | 0.03 | 0 B | - // CommonBulk | Core | 2048 | 17.022 us | 11.4894 us | 0.6492 us | 1.00 | 0.00 | 24 B | - // OptimizedBulk | Core | 2048 | 3.707 us | 0.1500 us | 0.0085 us | 0.22 | 0.01 | 0 B | + // | | | | | | | | | + // FastDefault | Core | 2048 | 14.693 us | 0.5131 us | 0.0290 us | 3.76 | 0.03 | 0 B | + // BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 3.913 us | 0.5661 us | 0.0320 us | 1.00 | 0.00 | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 1.966 us | 0.4056 us | 0.0229 us | 0.50 | 0.01 | 0 B | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 6afd3cf6b1..d699d168bb 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -29,8 +29,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, - //512 - 256 + //256, + //512, + 2048 )] public int Count { get; set; } @@ -60,70 +61,214 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - //[Benchmark] - public void CommonBulk() + [Benchmark] + public void PixelOperations_Base() { new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } - //[Benchmark] - public void OptimizedBulk() + [Benchmark] + public void PixelOperations_Specialized() { PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } - [RyuJitX64Job] - [DisassemblyDiagnoser(printAsm: true, printSource: true)] + [Config(typeof(Config.ShortClr))] public class ToVector4_Rgba32 : ToVector4 { - class Config : ManualConfig - { - } - - [Benchmark(Baseline = true)] - public void FastScalarBulk() + [Benchmark] + public void BasicBulk() { ref Rgba32 sBase = ref this.source.GetSpan()[0]; ref Vector4 dBase = ref this.destination.GetSpan()[0]; + Vector4 scale = new Vector4(1f / 255f); + + Vector4 v = default; + for (int i = 0; i < this.Count; i++) { ref Rgba32 s = ref Unsafe.Add(ref sBase, i); - ref Vector4 d = ref Unsafe.Add(ref dBase, i); - d.X = s.R; - d.Y = s.G; - d.Z = s.B; - d.W = s.A; + v.X = s.R; + v.Y = s.G; + v.Z = s.B; + v.W = s.A; + v *= scale; + Unsafe.Add(ref dBase, i) = v; + } + } + + [Benchmark(Baseline = true)] + public void BulkConvertByteToNormalizedFloat_2Loops() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + ref SimdUtils.Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref SimdUtils.Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dFloats)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dFloats.Length / 8; + + for (int i = 0; i < n; i++) + { + ref SimdUtils.Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + ref SimdUtils.Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); + d.LoadFrom(ref s); + } + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + df = vf; + } + } + + //[Benchmark] + public void BulkConvertByteToNormalizedFloat_ConvertInSameLoop() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + ref SimdUtils.Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref SimdUtils.Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dFloats)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dFloats.Length / 8; + + var temp = default(SimdUtils.Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + ref SimdUtils.Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + temp.LoadFrom(ref s); + + Vector vi = tempRef; + + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + Unsafe.Add(ref destBaseAsFloat, i) = vf; } } [Benchmark] - public void BulkConvertByteToNormalizedFloat() + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + + n = dFloats.Length / Vector.Count; + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector dRef = ref Unsafe.Add(ref destBase, i); + + Vector du = Vector.AsVectorInt32(dRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + dRef = v; + } } [Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat() + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = ConvertToNormalizedSingle(w0, scale); + Vector f1 = ConvertToNormalizedSingle(w1, scale); + Vector f2 = ConvertToNormalizedSingle(w2, scale); + Vector f3 = ConvertToNormalizedSingle(w3, scale); + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; } //[Benchmark] - public void Original() + public void OldImplementation() { - ToVector4SimdAligned(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + ToVector4OldImplementation(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ToVector4SimdAligned(ReadOnlySpan sourceColors, Span destVectors, int count) + private static void ToVector4OldImplementation(ReadOnlySpan sourceColors, Span destVectors, int count) { if (!Vector.IsHardwareAccelerated) { diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs index 4a4b939b65..be19e719a8 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { private float[] data; - private const int Count = 64; + private const int Count = 32; [GlobalSetup] public void Setup() @@ -24,8 +24,10 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization int n = Count / Vector.Count; - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); for (int i = 0; i < n; i++) { @@ -33,13 +35,16 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization // u.f = 32768.0f + x * (255.0f / 256.0f); // return (uint8_t)u.i; - ref Vector d = ref Unsafe.Add(ref b, i); - Vector x = d; - //x = Vector.Max(x, Vector.Zero); - //x = Vector.Min(x, Vector.One); + ref Vector df = ref Unsafe.Add(ref b, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; - x = (x * scale) + magick; - d = x; + df = vf; } } @@ -48,18 +53,37 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { int n = Count / Vector.Count; - ref Vector b = ref Unsafe.As>(ref this.data[0]); + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); var scale = new Vector(1f / 255f); for (int i = 0; i < n; i++) { - ref Vector df = ref Unsafe.Add(ref b, i); - Vector du = Unsafe.As, Vector>(ref df); + Vector u = Unsafe.Add(ref bu, i); + Vector v = Vector.ConvertToSingle(u); + v *= scale; + Unsafe.Add(ref bf, i) = v; + } + } - Vector v = Vector.ConvertToSingle(du); + // This code is not correct at all, it's just here as reference + [Benchmark] + public void StandardSimdFromInt() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector u = Unsafe.Add(ref bu, i); + Vector v = Vector.ConvertToSingle(u); v *= scale; - df = v; + Unsafe.Add(ref bf, i) = v; } } } diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 4b23ca30f1..7ed18ef86b 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -212,15 +212,11 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(3, 128)] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int seed, int count) { - if (!Vector.IsHardwareAccelerated) - { - return; - } - byte[] source = new Random(seed).GenerateRandomByteArray(count); float[] result = new float[count]; float[] expected = source.Select(b => (float)b / 255f).ToArray(); + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(source, result); Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); From 664d838291b5fc0aa3b975c7749023c69ebc8258 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 19:47:08 +0200 Subject: [PATCH 033/238] fix accuracy issues --- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 20 +++--- .../PixelFormats/Rgba32.PixelOperations.cs | 57 +++++++++++---- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 70 +++++++++---------- .../TestUtilities/TestDataGenerator.cs | 9 +-- 4 files changed, 91 insertions(+), 65 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 3131f18738..ec91e50988 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp { Guard.IsTrue( dest.Length % Vector.Count == 0, - nameof(source), + nameof(dest), "dest.Length should be divisable by Vector.Count!"); int n = dest.Length / Vector.Count; @@ -93,8 +93,6 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - Vector scale = new Vector(255); - for (int i = 0; i < n; i++) { ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); @@ -104,10 +102,10 @@ namespace SixLabors.ImageSharp Vector f2 = Unsafe.Add(ref s, 2); Vector f3 = Unsafe.Add(ref s, 3); - Vector w0 = ConvertToUInt32(f0, scale); - Vector w1 = ConvertToUInt32(f1, scale); - Vector w2 = ConvertToUInt32(f2, scale); - Vector w3 = ConvertToUInt32(f3, scale); + Vector w0 = ConvertToUInt32(f0); + Vector w1 = ConvertToUInt32(f1); + Vector w2 = ConvertToUInt32(f2); + Vector w3 = ConvertToUInt32(f3); Vector u0 = Vector.Narrow(w0, w1); Vector u1 = Vector.Narrow(w2, w3); @@ -119,10 +117,12 @@ namespace SixLabors.ImageSharp } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToUInt32(Vector vf, Vector scale) + private static Vector ConvertToUInt32(Vector vf) { - vf = Vector.Min(Vector.Max(vf, Vector.Zero), Vector.One); - vf *= scale; + Vector maxBytes = new Vector(255f); + vf *= maxBytes; + vf += new Vector(0.5f); + vf = Vector.Min(Vector.Max(vf, Vector.Zero), maxBytes); Vector vi = Vector.ConvertToInt32(vf); return Vector.AsVectorUInt32(vi); } diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 0b96a599b6..bfef60c606 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -52,22 +52,13 @@ namespace SixLabors.ImageSharp.PixelFormats return; } - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) + if (SimdUtils.ExtendedIntrinsics.IsAvailable) { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); - Span rawDest = MemoryMarshal.Cast(destinationColors); - - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); + ConvertFromVector4ExtendedIntrinsics(sourceVectors, destinationColors, count); } - - if (remainder > 0) + else { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); + ConvertFromVector4StandardIntrinsics(sourceVectors, destinationColors, count); } } @@ -144,6 +135,46 @@ namespace SixLabors.ImageSharp.PixelFormats destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); } } + + private static void ConvertFromVector4ExtendedIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) + { + int remainder = count % 8; + int alignedCount = count - remainder; + + if (alignedCount > 0) + { + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors); + Span rawDest = MemoryMarshal.Cast(destinationColors.Slice(0, alignedCount)); + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); + } + + if (remainder > 0) + { + PackFromVector4Common(sourceVectors.Slice(alignedCount), destinationColors.Slice(alignedCount), remainder); + } + } + + private static void ConvertFromVector4StandardIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) + { + int remainder = count % 2; + int alignedCount = count - remainder; + + if (alignedCount > 0) + { + ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); + Span rawDest = MemoryMarshal.Cast(destinationColors); + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); + } + + if (remainder > 0) + { + // actually: remainder == 1 + int lastIdx = count - 1; + destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); + } + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 7ed18ef86b..4e1717bda9 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -160,31 +160,6 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, dest); } - private static float Clamp255(float x) => Math.Min(255f, Math.Max(0f, x)); - - [Theory] - [InlineData(1, 0)] - [InlineData(1, 8)] - [InlineData(2, 16)] - [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count) - { - if (this.SkipOnNonAvx2()) - { - return; - } - - float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444); - float[] normalized = orig.Select(f => f / 255f).ToArray(); - - byte[] dest = new byte[count]; - - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest); - - byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray(); - - Assert.Equal(expected, dest); - } [Theory] [InlineData(1, 0)] @@ -222,23 +197,44 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } + + public static readonly TheoryData BulkConvertNormalizedFloatToByteClampOverflows_Data = + new TheoryData + { + 0, 64, 1024 + }; + [Theory] - [InlineData(1, 0)] - [InlineData(2, 32)] - [InlineData(3, 128)] - public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count) + [MemberData(nameof(BulkConvertNormalizedFloatToByteClampOverflows_Data))] + public void BulkConvertNormalizedFloatToByteClampOverflows(int count) { - float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444); - float[] normalized = orig.Select(f => f / 255f).ToArray(); + if (this.SkipOnNonAvx2()) + { + return; + } - byte[] dest = new byte[count]; + float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); + byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); + byte[] actual = new byte[count]; - SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest); + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(source, actual); - byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray(); + Assert.Equal(expected, actual); + } - Assert.Equal(expected, dest); + [Theory] + [MemberData(nameof(BulkConvertNormalizedFloatToByteClampOverflows_Data))] + public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); + byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); + byte[] actual = new byte[count]; + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(source, actual); + + Assert.Equal(expected, actual); } + private static byte NormalizedFloatToByte(float f) => (byte)Math.Min(255f, Math.Max(0f, f * 255f + 0.5f)); [Theory] [InlineData(0)] @@ -265,7 +261,7 @@ namespace SixLabors.ImageSharp.Tests.Common float[] source = { 0, 7, 42, 255, 0.5f, 1.1f, 2.6f, 16f }; - var expected = source.Select(f => (byte)Math.Round(f)).ToArray(); + byte[] expected = source.Select(f => (byte)Math.Round(f)).ToArray(); source = source.Select(f => f / 255f).ToArray(); @@ -299,8 +295,6 @@ namespace SixLabors.ImageSharp.Tests.Common iiRef = x; - //Tuple8.OfUInt32 ii = Unsafe.As, Tuple8.OfUInt32>(ref x); - ref Tuple8.OfByte d = ref MemoryMarshal.Cast(dest)[0]; d.LoadFrom(ref ii); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 6f3b18e1fc..912b86e347 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -33,19 +33,20 @@ namespace SixLabors.ImageSharp.Tests return values; } - public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, int minVal, int maxValExclusive) + public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; for (int i = 0; i < length; i++) { - int val = rnd.Next(minVal, maxValExclusive); - values[i] = (float)val; + values[i] = (float) Math.Round(rnd.GetRandomFloat(minVal, maxVal)); } return values; } + + public static byte[] GenerateRandomByteArray(this Random rnd, int length) { byte[] values = new byte[length]; @@ -53,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests return values; } - private static float GetRandomFloat(Random rnd, float minVal, float maxVal) + private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) { return (float)rnd.NextDouble() * (maxVal - minVal) + minVal; } From 10afe6572e598274e89ba8851b87732eb2f6d6fc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 20:05:20 +0200 Subject: [PATCH 034/238] cleanup benchmarks --- .../Color/Bulk/ToVector4.cs | 96 ++----------------- 1 file changed, 10 insertions(+), 86 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index d699d168bb..726e214a96 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -100,84 +100,24 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void BulkConvertByteToNormalizedFloat_2Loops() + public void BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - ref SimdUtils.Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref SimdUtils.Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dFloats)); - - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); - - int n = dFloats.Length / 8; - - for (int i = 0; i < n; i++) - { - ref SimdUtils.Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); - ref SimdUtils.Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); - d.LoadFrom(ref s); - } - - for (int i = 0; i < n; i++) - { - ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); - - var vi = Vector.AsVectorUInt32(df); - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - df = vf; - } + SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - //[Benchmark] - public void BulkConvertByteToNormalizedFloat_ConvertInSameLoop() + [Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - ref SimdUtils.Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref SimdUtils.Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dFloats)); - - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); - - int n = dFloats.Length / 8; - - var temp = default(SimdUtils.Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - ref SimdUtils.Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); - temp.LoadFrom(ref s); - - Vector vi = tempRef; - - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - Unsafe.Add(ref destBaseAsFloat, i) = vf; - } + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - [Benchmark] + //[Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -219,7 +159,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + //[Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -264,23 +204,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk //[Benchmark] public void OldImplementation() { - ToVector4OldImplementation(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ToVector4OldImplementation(ReadOnlySpan sourceColors, Span destVectors, int count) - { - if (!Vector.IsHardwareAccelerated) - { - throw new InvalidOperationException( - "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); - } - - DebugGuard.IsTrue( - count % Vector.Count == 0, - nameof(count), - "Argument 'count' should divisible by Vector.Count!"); - + int count = this.Count; var bVec = new Vector(256.0f / 255.0f); var magicFloat = new Vector(32768.0f); var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f @@ -288,8 +212,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk int unpackedRawCount = count * 4; - ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); - ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); + ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)this.source.GetSpan())); + ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(this.destination.GetSpan())); ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); From 17f6dcc877f720848ca9d21a443c341c22bfaf87 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 22:49:31 +0200 Subject: [PATCH 035/238] Bulk conversion of arbitrary-sized Span-s of scalars --- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 212 +++++++++++++++ .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 90 +++++-- src/ImageSharp/Common/Helpers/SimdUtils.cs | 255 +++--------------- src/ImageSharp/Common/Tuples/Octet.cs | 100 +++++++ src/ImageSharp/Common/Tuples/Vector4Pair.cs | 2 +- .../JpegColorConverter.FromYCbCrSimd.cs | 2 +- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 2 +- .../ColorConverters/JpegColorConverter.cs | 2 +- .../PixelFormats/Rgba32.PixelOperations.cs | 12 +- .../Color/Bulk/ToVector4.cs | 8 +- .../General/Vectorization/UInt32ToSingle.cs | 27 +- .../Vectorization/WidenBytesToUInt32.cs | 7 +- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 108 +++++--- 13 files changed, 537 insertions(+), 290 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs create mode 100644 src/ImageSharp/Common/Tuples/Octet.cs diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs new file mode 100644 index 0000000000..e4dc1a1d8f --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -0,0 +1,212 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Tuples; + +// ReSharper disable MemberHidesStaticFromOuterClass +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*) + /// + public static class BasicIntrinsics256 + { + public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture; + + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (IsAvailable) + { + int remainder = source.Length % 8; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, alignedCount), + dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + } + + /// + /// Convert 'source.Length' values normalized into [0..1] from 'source' + /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. + /// The implementation is SIMD optimized and works only with `source.Length` divisible by 8/>. + /// Based on: + /// + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// + /// + internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); + + DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } + + /// + /// SIMD optimized implementation for . + /// Works only with `dest.Length` divisible by 8. + /// Implementation adapted from: + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// http://stackoverflow.com/a/536278 + /// + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); + + DebugGuard.IsTrue((dest.Length % 8) == 0, nameof(source), "dest.Length should be divisable by 8!"); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dest.Length / 8; + + for (int i = 0; i < n; i++) + { + ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); + d.LoadFrom(ref s); + } + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + df = vf; + } + } + + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (IsAvailable) + { + int remainder = source.Length % Vector.Count; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + } + + /// + /// Same as but clamps overflown values before conversion. + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); + + DebugGuard.IsTrue((source.Length % 8) == 0, nameof(source), "source.Length should be divisible by 8!"); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = Vector.Max(x, Vector.Zero); + x = Vector.Min(x, Vector.One); + + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index ec91e50988..5c0b8ee93a 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -1,8 +1,10 @@ using System; +using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +// ReSharper disable MemberHidesStaticFromOuterClass namespace SixLabors.ImageSharp { internal static partial class SimdUtils @@ -18,22 +20,47 @@ namespace SixLabors.ImageSharp { public static bool IsAvailable { get; } = #if NETCOREAPP2_1 -// TODO: Also available in .NET 4.7.2, we need to add a build target! - true; + // TODO: Also available in .NET 4.7.2, we need to add a build target! + Vector.IsHardwareAccelerated; #else false; #endif /// - /// A variant of , which is faster on new .NET runtime. + /// as much elements as possible, slicing them down (keeping the remainder). + /// + [Conditional("NETCOREAPP2_1")] + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (IsAvailable) + { + int remainder = source.Length % Vector.Count; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertByteToNormalizedFloat(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + } + + /// + /// A variant of , which is faster on new RyuJIT runtime. /// // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - Guard.IsTrue( + DebugGuard.IsTrue( dest.Length % Vector.Count == 0, nameof(source), - "dest.Length should be divisable by Vector.Count!"); + "dest.Length should be divisible by Vector.Count!"); int n = dest.Length / Vector.Count; @@ -63,34 +90,52 @@ namespace SixLabors.ImageSharp } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToSingle(Vector u, Vector scale) + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + [Conditional("NETCOREAPP2_1")] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) { - Vector vi = Vector.AsVectorInt32(u); - Vector v = Vector.ConvertToSingle(vi); - v *= scale; - return v; + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (IsAvailable) + { + int remainder = source.Length % Vector.Count; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } } /// - /// A variant of , which is faster on new .NET runtime. + /// A variant of , which is faster on new .NET runtime. /// /// /// It does NOT worth yet to utilize this method (2018 Oct). /// See benchmark results for the "PackFromVector4_Rgba32" benchmark! /// TODO: Check again later! /// - // ReSharper disable once MemberHidesStaticFromOuterClass - internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + internal static void BulkConvertNormalizedFloatToByteClampOverflows( + ReadOnlySpan source, + Span dest) { - Guard.IsTrue( + DebugGuard.IsTrue( dest.Length % Vector.Count == 0, nameof(dest), - "dest.Length should be divisable by Vector.Count!"); + "dest.Length should be divisible by Vector.Count!"); int n = dest.Length / Vector.Count; - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector sourceBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); for (int i = 0; i < n; i++) @@ -126,6 +171,15 @@ namespace SixLabors.ImageSharp Vector vi = Vector.ConvertToInt32(vf); return Vector.AsVectorUInt32(vi); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; + } } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 91aed8c79a..73e9bacfa8 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -6,6 +6,9 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tuples; + namespace SixLabors.ImageSharp { /// @@ -16,7 +19,8 @@ namespace SixLabors.ImageSharp /// /// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte. /// - public static bool IsAvx2CompatibleArchitecture { get; } = Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; + public static bool IsAvx2CompatibleArchitecture { get; } = + Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; internal static void GuardAvx2(string operation) { @@ -57,236 +61,61 @@ namespace SixLabors.ImageSharp } /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of values. - /// The values are scaled up into [0-255] and rounded. - /// The implementation is SIMD optimized and works only with `source.Length` divisible by . - /// Based on: - /// - /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions - /// - /// - internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) - { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - - /// - /// Converts `dest.Length` bytes to -s to -s normalized into [0..1] - /// The implementation is SIMD optimized and works only with `dest.Length` divisible by . - /// Implementation adapted from: - /// - /// http://stackoverflow.com/a/5362789 - /// + /// Converts `dest.Length` -s to -s normalized into [0..1]. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. /// internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); - - DebugGuard.IsTrue((dest.Length % Vector.Count) == 0, nameof(source), "dest.Length should be divisable by Vector.Count!"); - - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); - - int n = dest.Length / 8; - - for (int i = 0; i < n; i++) - { - ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); - ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); - d.LoadFrom(ref s); - } + ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); + BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); - for (int i = 0; i < n; i++) + // Deal with the remainder: + int count = source.Length; + if (count > 0) { - ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); - - var vi = Vector.AsVectorUInt32(df); - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - df = vf; + // TODO: Do we need to optimize anything on this? (There are at most 7 remainders) + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref float dBase = ref MemoryMarshal.GetReference(dest); + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i) / 255f; + } } } /// - /// Same as but clamps overflown values before conversion. + /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of . + /// The values are scaled up into [0-255] and rounded, overflows are clamped. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. /// internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = Vector.Max(x, Vector.Zero); - x = Vector.Min(x, Vector.One); - - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - - // TODO: Replace these with T4-d library level tuples! - internal static class Octet - { - [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] - public struct OfUInt32 - { - [FieldOffset(0 * sizeof(uint))] - public uint V0; - - [FieldOffset(1 * sizeof(uint))] - public uint V1; - - [FieldOffset(2 * sizeof(uint))] - public uint V2; - - [FieldOffset(3 * sizeof(uint))] - public uint V3; - - [FieldOffset(4 * sizeof(uint))] - public uint V4; - - [FieldOffset(5 * sizeof(uint))] - public uint V5; + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - [FieldOffset(6 * sizeof(uint))] - public uint V6; + ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); - [FieldOffset(7 * sizeof(uint))] - public uint V7; - - public override string ToString() - { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; - } - - [MethodImpl(InliningOptions.ShortMethod)] - public void LoadFrom(ref OfByte src) - { - this.V0 = src.V0; - this.V1 = src.V1; - this.V2 = src.V2; - this.V3 = src.V3; - this.V4 = src.V4; - this.V5 = src.V5; - this.V6 = src.V6; - this.V7 = src.V7; - } - } - - [StructLayout(LayoutKind.Explicit, Size = 8)] - public struct OfByte + // Deal with the remainder: + int count = source.Length; + if (count > 0) { - [FieldOffset(0)] - public byte V0; - - [FieldOffset(1)] - public byte V1; - - [FieldOffset(2)] - public byte V2; - - [FieldOffset(3)] - public byte V3; - - [FieldOffset(4)] - public byte V4; - - [FieldOffset(5)] - public byte V5; - - [FieldOffset(6)] - public byte V6; - - [FieldOffset(7)] - public byte V7; - - public override string ToString() - { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; - } + ref float sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(dest); - [MethodImpl(InliningOptions.ShortMethod)] - public void LoadFrom(ref OfUInt32 src) + for (int i = 0; i < count; i++) { - this.V0 = (byte)src.V0; - this.V1 = (byte)src.V1; - this.V2 = (byte)src.V2; - this.V3 = (byte)src.V3; - this.V4 = (byte)src.V4; - this.V5 = (byte)src.V5; - this.V6 = (byte)src.V6; - this.V7 = (byte)src.V7; + // TODO: Do we need to optimize anything on this? (There are at most 7 remainders) + float f = Unsafe.Add(ref sBase, i); + f *= 255f; + f += 0.5f; + f = MathF.Max(0, f); + f = MathF.Min(255f, f); + + Unsafe.Add(ref dBase, i) = (byte)f; } } } diff --git a/src/ImageSharp/Common/Tuples/Octet.cs b/src/ImageSharp/Common/Tuples/Octet.cs new file mode 100644 index 0000000000..ae01a31217 --- /dev/null +++ b/src/ImageSharp/Common/Tuples/Octet.cs @@ -0,0 +1,100 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Tuples +{ + internal static class Octet + { + [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] + public struct OfUInt32 + { + [FieldOffset(0 * sizeof(uint))] + public uint V0; + + [FieldOffset(1 * sizeof(uint))] + public uint V1; + + [FieldOffset(2 * sizeof(uint))] + public uint V2; + + [FieldOffset(3 * sizeof(uint))] + public uint V3; + + [FieldOffset(4 * sizeof(uint))] + public uint V4; + + [FieldOffset(5 * sizeof(uint))] + public uint V5; + + [FieldOffset(6 * sizeof(uint))] + public uint V6; + + [FieldOffset(7 * sizeof(uint))] + public uint V7; + + public override string ToString() + { + return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfByte src) + { + this.V0 = src.V0; + this.V1 = src.V1; + this.V2 = src.V2; + this.V3 = src.V3; + this.V4 = src.V4; + this.V5 = src.V5; + this.V6 = src.V6; + this.V7 = src.V7; + } + } + + [StructLayout(LayoutKind.Explicit, Size = 8)] + public struct OfByte + { + [FieldOffset(0)] + public byte V0; + + [FieldOffset(1)] + public byte V1; + + [FieldOffset(2)] + public byte V2; + + [FieldOffset(3)] + public byte V3; + + [FieldOffset(4)] + public byte V4; + + [FieldOffset(5)] + public byte V5; + + [FieldOffset(6)] + public byte V6; + + [FieldOffset(7)] + public byte V7; + + public override string ToString() + { + return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfUInt32 src) + { + this.V0 = (byte)src.V0; + this.V1 = (byte)src.V1; + this.V2 = (byte)src.V2; + this.V3 = (byte)src.V3; + this.V4 = (byte)src.V4; + this.V5 = (byte)src.V5; + this.V6 = (byte)src.V6; + this.V7 = (byte)src.V7; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index 309d5e2e56..5988b2200b 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -2,7 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Common.Tuples +namespace SixLabors.ImageSharp.Tuples { /// /// Its faster to process multiple Vector4-s together, so let's pair them! diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index 4b2626c582..5c63a478db 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Tuples; +using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index ab4947e65c..3f26cdc907 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Tuples; +using SixLabors.ImageSharp.Tuples; // ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 60abb7fb2c..293f3bc1f7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -6,8 +6,8 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Tuples; using SixLabors.Memory; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index bfef60c606..564b93ef52 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats } else { - ConvertToVector4UsingStandardIntrinsics(sourceColors, destinationVectors, count); + ConvertToVector4UsingBasicIntrinsics(sourceColors, destinationVectors, count); } } @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.PixelFormats } else { - ConvertFromVector4StandardIntrinsics(sourceVectors, destinationColors, count); + ConvertFromVector4BasicIntrinsics(sourceVectors, destinationColors, count); } } @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.PixelFormats } } - private static void ConvertToVector4UsingStandardIntrinsics( + private static void ConvertToVector4UsingBasicIntrinsics( ReadOnlySpan sourceColors, Span destinationVectors, int count) @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); - SimdUtils.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); + SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); } if (remainder > 0) @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.PixelFormats } } - private static void ConvertFromVector4StandardIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) + private static void ConvertFromVector4BasicIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) { int remainder = count % 2; int alignedCount = count - remainder; @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.PixelFormats ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); Span rawDest = MemoryMarshal.Cast(destinationColors); - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); } if (remainder > 0) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 726e214a96..855e9e4b97 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -30,8 +30,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, //256, - //512, - 2048 + 512 + //1024 )] public int Count { get; set; } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - //[Benchmark] + [Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - //[Benchmark] + [Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs index be19e719a8..ca85a350cc 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -5,6 +5,7 @@ using BenchmarkDotNet.Attributes; namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { + [Config(typeof(Config.ShortClr))] public class UInt32ToSingle { private float[] data; @@ -66,8 +67,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization Unsafe.Add(ref bf, i) = v; } } - - // This code is not correct at all, it's just here as reference + [Benchmark] public void StandardSimdFromInt() { @@ -86,5 +86,28 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization Unsafe.Add(ref bf, i) = v; } } + + + [Benchmark] + public void StandardSimdFromInt_RefCast() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector fRef = ref Unsafe.Add(ref bf, i); + + Vector du = Vector.AsVectorInt32(fRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + fRef = v; + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs index f71f6ec1bf..2bc3af4c98 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs @@ -3,8 +3,11 @@ using System.Runtime.CompilerServices; using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Tuples; + namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { + [Config(typeof(Config.ShortClr))] public class WidenBytesToUInt32 { private byte[] source; @@ -25,8 +28,8 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { const int N = Count / 8; - ref SimdUtils.Octet.OfByte sBase = ref Unsafe.As(ref this.source[0]); - ref SimdUtils.Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + ref Octet.OfByte sBase = ref Unsafe.As(ref this.source[0]); + ref Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); for (int i = 0; i < N; i++) { diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 4e1717bda9..2dcba2b74b 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Common { float[] data = new float[Vector.Count]; - var rnd = new Random(); + var rnd = new Random(seed); for (int i = 0; i < Vector.Count; i++) { @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) + public void BasicIntrinsics_BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests.Common byte[] dest = new byte[count]; - SimdUtils.BulkConvertNormalizedFloatToByte(normalized, dest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByte(normalized, dest); byte[] expected = orig.Select(f => (byte)(f)).ToArray(); @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) + public void BasicIntrinsics_BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -153,87 +153,113 @@ namespace SixLabors.ImageSharp.Tests.Common byte[] dest = new byte[count]; - SimdUtils.BulkConvertNormalizedFloatToByte(source, dest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByte(source, dest); byte[] expected = source.Select(f => (byte)Math.Round(f * 255f)).ToArray(); Assert.Equal(expected, dest); } + public static readonly TheoryData ArraySizesDivisibleBy8 = new TheoryData { 0, 8, 16, 1024 }; + + public static readonly TheoryData ArraySizesDivisibleBy32 = new TheoryData { 0, 32, 512 }; + + public static readonly TheoryData ArbitraryArraySizes = + new TheoryData + { + 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 520, + }; [Theory] - [InlineData(1, 0)] - [InlineData(2, 32)] - [InlineData(3, 128)] - public void BulkConvertByteToNormalizedFloat(int seed, int count) + [MemberData(nameof(ArraySizesDivisibleBy8))] + public void BasicIntrinsics_BulkConvertByteToNormalizedFloat(int count) { if (this.SkipOnNonAvx2()) { return; } - byte[] source = new Random(seed).GenerateRandomByteArray(count); - float[] result = new float[count]; - float[] expected = source.Select(b => (float)b / 255f).ToArray(); - - SimdUtils.BulkConvertByteToNormalizedFloat(source, result); - - Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); } [Theory] - [InlineData(1, 0)] - [InlineData(2, 32)] - [InlineData(3, 128)] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int seed, int count) + [MemberData(nameof(ArraySizesDivisibleBy32))] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + + [Theory] + [MemberData(nameof(ArbitraryArraySizes))] + public void BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + + private static void TestImpl_BulkConvertByteToNormalizedFloat( + int count, + Action, Memory> convert) { - byte[] source = new Random(seed).GenerateRandomByteArray(count); + byte[] source = new Random(count).GenerateRandomByteArray(count); float[] result = new float[count]; float[] expected = source.Select(b => (float)b / 255f).ToArray(); - - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(source, result); + convert(source, result); Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } - - public static readonly TheoryData BulkConvertNormalizedFloatToByteClampOverflows_Data = - new TheoryData - { - 0, 64, 1024 - }; - [Theory] - [MemberData(nameof(BulkConvertNormalizedFloatToByteClampOverflows_Data))] - public void BulkConvertNormalizedFloatToByteClampOverflows(int count) + [MemberData(nameof(ArraySizesDivisibleBy8))] + public void BasicIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) { if (this.SkipOnNonAvx2()) { return; } - float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); - byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); - byte[] actual = new byte[count]; - - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(source, actual); - - Assert.Equal(expected, actual); + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); } [Theory] - [MemberData(nameof(BulkConvertNormalizedFloatToByteClampOverflows_Data))] + [MemberData(nameof(ArraySizesDivisibleBy32))] public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + [Theory] + [MemberData(nameof(ArbitraryArraySizes))] + public void BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + private static void TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( + int count, + Action, Memory> convert) { float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); byte[] actual = new byte[count]; - SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(source, actual); + convert(source, actual); Assert.Equal(expected, actual); } + private static byte NormalizedFloatToByte(float f) => (byte)Math.Min(255f, Math.Max(0f, f * 255f + 0.5f)); [Theory] From 34ab918624f802989629402d0825a28aca82a634 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 20 Oct 2018 23:31:21 +0200 Subject: [PATCH 036/238] fix benchmarks --- .../Color/Bulk/PackFromVector4.cs | 4 +- .../Color/Bulk/ToVector4.cs | 73 ++----------------- 2 files changed, 8 insertions(+), 69 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index 1153d8f401..eb7154955e 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -95,12 +95,12 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void BulkConvertNormalizedFloatToByteClampOverflows() + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } [Benchmark] diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 855e9e4b97..c50c7ce5ad 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -30,8 +30,9 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( //64, //256, - 512 - //1024 + //512, + //1024, + 2048 )] public int Count { get; set; } @@ -100,12 +101,12 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void BulkConvertByteToNormalizedFloat() + public void BasicIntrinsics256_BulkConvertByteToNormalizedFloat() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } [Benchmark] @@ -117,7 +118,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - [Benchmark] + //[Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -200,67 +201,5 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk v *= scale; return v; } - - //[Benchmark] - public void OldImplementation() - { - int count = this.Count; - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - int unpackedRawCount = count * 4; - - ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference((ReadOnlySpan)this.source.GetSpan())); - ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(this.destination.GetSpan())); - ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); - - for (int i = 0; i < count; i++) - { - uint sVal = Unsafe.Add(ref sourceBase, i); - ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i); - - // This call is the bottleneck now: - dst.Load(sVal); - } - - int numOfVectors = unpackedRawCount / Vector.Count; - - for (int i = 0; i < numOfVectors; i++) - { - Vector vi = Unsafe.Add(ref destBaseAsUInt, i); - - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - Unsafe.Add(ref destBaseAsFloat, i) = vf; - } - } - - [StructLayout(LayoutKind.Sequential)] - private struct UnpackedRGBA - { - private uint r; - - private uint g; - - private uint b; - - private uint a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Load(uint p) - { - this.r = p; - this.g = p >> 8; - this.b = p >> 16; - this.a = p >> 24; - } - } } } \ No newline at end of file From 2fcda3cee0d4091678bf4a41bfcfa2b88a444949 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 01:21:36 +0200 Subject: [PATCH 037/238] simplify Rgba32.PixelOperations, include benchmark results --- .../PixelFormats/PixelOperations{TPixel}.cs | 60 ++++----- .../PixelFormats/Rgba32.PixelOperations.cs | 123 ++---------------- .../Color/Bulk/PackFromVector4.cs | 41 ++++-- .../Color/Bulk/ToVector4.cs | 32 ++++- 4 files changed, 94 insertions(+), 162 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 39c442fe02..cbf164a71c 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -29,7 +29,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - PackFromVector4Common(sourceVectors, destinationColors, count); + ReadOnlySpan sourceVectors1 = sourceVectors; + Span destinationColors1 = destinationColors; + GuardSpans(sourceVectors1, nameof(sourceVectors1), destinationColors1, nameof(destinationColors1), count); + + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors1); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors1); + + for (int i = 0; i < count; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.PackFromVector4(sp); + } } /// @@ -40,7 +52,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { - ToVector4Common(sourceColors, destinationVectors, count); + ReadOnlySpan sourceColors1 = sourceColors; + Span destinationVectors1 = destinationVectors; + GuardSpans(sourceColors1, nameof(sourceColors1), destinationVectors1, nameof(destinationVectors1), count); + + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors1); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors1); + + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } } /// @@ -106,37 +130,5 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName); } - - [MethodImpl(InliningOptions.ShortMethod)] - internal static void PackFromVector4Common(ReadOnlySpan sourceVectors, Span destinationColors, int count) - { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - - for (int i = 0; i < count; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromVector4(sp); - } - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal static void ToVector4Common(ReadOnlySpan sourceColors, Span destinationVectors, int count) - { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); - - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs index 564b93ef52..bb42ec7e34 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs @@ -24,21 +24,12 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) - { - // Doesn't worth to bother with SIMD: - ToVector4Common(sourceColors, destinationVectors, count); - return; - } + sourceColors = sourceColors.Slice(0, count); + destinationVectors = destinationVectors.Slice(0, count); - if (SimdUtils.ExtendedIntrinsics.IsAvailable) - { - ConvertToVector4UsingExtendedIntrinsics(sourceColors, destinationVectors, count); - } - else - { - ConvertToVector4UsingBasicIntrinsics(sourceColors, destinationVectors, count); - } + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(sourceColors), + MemoryMarshal.Cast(destinationVectors)); } /// @@ -46,20 +37,12 @@ namespace SixLabors.ImageSharp.PixelFormats { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - if (count < 128 || !SimdUtils.IsAvx2CompatibleArchitecture) - { - PackFromVector4Common(sourceVectors, destinationColors, count); - return; - } + sourceVectors = sourceVectors.Slice(0, count); + destinationColors = destinationColors.Slice(0, count); - if (SimdUtils.ExtendedIntrinsics.IsAvailable) - { - ConvertFromVector4ExtendedIntrinsics(sourceVectors, destinationColors, count); - } - else - { - ConvertFromVector4BasicIntrinsics(sourceVectors, destinationColors, count); - } + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(destinationColors)); } /// @@ -89,92 +72,6 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(dest); } - - private static void ConvertToVector4UsingExtendedIntrinsics( - ReadOnlySpan sourceColors, - Span destinationVectors, - int count) - { - int remainder = count % 8; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); - Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); - - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); - } - - if (remainder > 0) - { - ToVector4Common(sourceColors.Slice(alignedCount), destinationVectors.Slice(alignedCount), remainder); - } - } - - private static void ConvertToVector4UsingBasicIntrinsics( - ReadOnlySpan sourceColors, - Span destinationVectors, - int count) - { - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceColors); - Span rawDest = MemoryMarshal.Cast(destinationVectors.Slice(0, alignedCount)); - - SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(rawSrc, rawDest); - } - - if (remainder > 0) - { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationVectors[lastIdx] = sourceColors[lastIdx].ToVector4(); - } - } - - private static void ConvertFromVector4ExtendedIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) - { - int remainder = count % 8; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors); - Span rawDest = MemoryMarshal.Cast(destinationColors.Slice(0, alignedCount)); - - SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); - } - - if (remainder > 0) - { - PackFromVector4Common(sourceVectors.Slice(alignedCount), destinationColors.Slice(alignedCount), remainder); - } - } - - private static void ConvertFromVector4BasicIntrinsics(ReadOnlySpan sourceVectors, Span destinationColors, int count) - { - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan rawSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); - Span rawDest = MemoryMarshal.Cast(destinationColors); - - SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(rawSrc, rawDest); - } - - if (remainder > 0) - { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); - } - } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index eb7154955e..7a212b0523 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; [Params( - //64, + 64, 2048 )] public int Count { get; set; } @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class PackFromVector4_Rgba32 : PackFromVector4 { [Benchmark] - public void FastDefault() + public void BasicBulk() { ref Vector4 sBase = ref this.source.GetSpan()[0]; ref Rgba32 dBase = ref this.destination.GetSpan()[0]; @@ -112,16 +112,31 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } - // RESULTS: - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | - // ----------------------------------------------------------------- |-------- |------ |----------:|----------:|----------:|-------:|---------:|----------:| - // FastDefault | Clr | 2048 | 15.989 us | 6.1384 us | 0.3468 us | 4.07 | 0.08 | 0 B | - // BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3.931 us | 0.6264 us | 0.0354 us | 1.00 | 0.00 | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 2.100 us | 0.4717 us | 0.0267 us | 0.53 | 0.01 | 0 B | - // - // | | | | | | | | | - // FastDefault | Core | 2048 | 14.693 us | 0.5131 us | 0.0290 us | 3.76 | 0.03 | 0 B | - // BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 3.913 us | 0.5661 us | 0.0320 us | 1.00 | 0.00 | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 1.966 us | 0.4056 us | 0.0229 us | 0.50 | 0.01 | 0 B | + // RESULTS (2018 October): + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ------------------------------------------------------------------ |-------- |------ |-------------:|-------------:|-----------:|-------:|---------:|-------:|----------:| + // BasicBulk | Clr | 64 | 581.62 ns | 33.625 ns | 1.8999 ns | 2.27 | 0.02 | - | 0 B | + // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 64 | 256.66 ns | 45.153 ns | 2.5512 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 64 | 201.92 ns | 30.161 ns | 1.7042 ns | 0.79 | 0.01 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 665.01 ns | 13.032 ns | 0.7363 ns | 2.59 | 0.02 | 0.0067 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 295.14 ns | 26.335 ns | 1.4880 ns | 1.15 | 0.01 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Core | 64 | 513.22 ns | 91.110 ns | 5.1479 ns | 3.19 | 0.03 | - | 0 B | + // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Core | 64 | 160.76 ns | 2.760 ns | 0.1559 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 64 | 95.98 ns | 10.077 ns | 0.5694 ns | 0.60 | 0.00 | - | 0 B | + // PixelOperations_Base | Core | 64 | 591.74 ns | 49.856 ns | 2.8170 ns | 3.68 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 64 | 149.11 ns | 4.485 ns | 0.2534 ns | 0.93 | 0.00 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Clr | 2048 | 15,345.85 ns | 1,213.551 ns | 68.5679 ns | 3.90 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3,939.49 ns | 71.101 ns | 4.0173 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 2,272.61 ns | 110.671 ns | 6.2531 ns | 0.58 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 2048 | 17,422.47 ns | 811.733 ns | 45.8644 ns | 4.42 | 0.01 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 3,984.26 ns | 110.352 ns | 6.2351 ns | 1.01 | 0.00 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Core | 2048 | 14,950.43 ns | 699.309 ns | 39.5123 ns | 3.76 | 0.02 | - | 0 B | + // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 3,978.28 ns | 481.105 ns | 27.1833 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 2,169.54 ns | 75.606 ns | 4.2719 ns | !!0.55!| 0.00 | - | 0 B | + // PixelOperations_Base | Core | 2048 | 18,403.62 ns | 1,494.056 ns | 84.4169 ns | 4.63 | 0.03 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,227.60 ns | 486.761 ns | 27.5029 ns | !!0.56!| 0.01 | - | 0 B | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index c50c7ce5ad..4a801d64ef 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; [Params( - //64, + 64, //256, //512, //1024, @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + //[Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -201,5 +201,33 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk v *= scale; return v; } + + // RESULTS (2018 October): + // + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------------------------------- |-------- |------ |------------:|-------------:|-----------:|-------:|---------:|-------:|----------:| + // BasicBulk | Clr | 64 | 267.40 ns | 30.711 ns | 1.7352 ns | 1.07 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Clr | 64 | 249.97 ns | 33.838 ns | 1.9119 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Clr | 64 | 176.97 ns | 5.221 ns | 0.2950 ns | 0.71 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 349.70 ns | 104.331 ns | 5.8949 ns | 1.40 | 0.02 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 288.31 ns | 26.833 ns | 1.5161 ns | 1.15 | 0.01 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Core | 64 | 185.36 ns | 30.051 ns | 1.6979 ns | 1.26 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Core | 64 | 146.84 ns | 12.674 ns | 0.7161 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Core | 64 | 67.31 ns | 2.542 ns | 0.1436 ns | 0.46 | 0.00 | - | 0 B | + // PixelOperations_Base | Core | 64 | 272.03 ns | 94.419 ns | 5.3348 ns | 1.85 | 0.03 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 121.91 ns | 31.477 ns | 1.7785 ns | 0.83 | 0.01 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Clr | 2048 | 5,133.04 ns | 284.052 ns | 16.0494 ns | 1.21 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Clr | 2048 | 4,248.58 ns | 1,095.887 ns | 61.9196 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Clr | 2048 | 1,214.02 ns | 184.349 ns | 10.4160 ns | 0.29 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 2048 | 7,096.04 ns | 362.350 ns | 20.4734 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 4,314.19 ns | 204.964 ns | 11.5809 ns | 1.02 | 0.01 | - | 0 B | + // | | | | | | | | | | + // BasicBulk | Core | 2048 | 5,038.38 ns | 223.282 ns | 12.6158 ns | 1.20 | 0.01 | - | 0 B | + // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Core | 2048 | 4,199.17 ns | 897.985 ns | 50.7378 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Core | 2048 | 1,113.86 ns | 64.799 ns | 3.6613 ns | !!0.27!| 0.00 | - | 0 B | + // PixelOperations_Base | Core | 2048 | 7,015.00 ns | 920.083 ns | 51.9864 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 1,176.59 ns | 256.955 ns | 14.5184 ns | !!0.28!| 0.00 | - | 0 B | } } \ No newline at end of file From cb8b48dcbaf0e4fc3f5d7402b7b488f1c9a0ce3d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 01:31:55 +0200 Subject: [PATCH 038/238] cleanup code and comments --- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 96 +++++++++---------- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 10 +- src/ImageSharp/Common/Helpers/SimdUtils.cs | 28 +++--- 3 files changed, 67 insertions(+), 67 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index e4dc1a1d8f..a8b3434980 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -46,53 +46,6 @@ namespace SixLabors.ImageSharp } } - /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' - /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. - /// The implementation is SIMD optimized and works only with `source.Length` divisible by 8/>. - /// Based on: - /// - /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions - /// - /// - internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) - { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - /// /// SIMD optimized implementation for . /// Works only with `dest.Length` divisible by 8. @@ -165,7 +118,7 @@ namespace SixLabors.ImageSharp } /// - /// Same as but clamps overflown values before conversion. + /// Implementation of which is faster on older runtimes. /// internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { @@ -207,6 +160,53 @@ namespace SixLabors.ImageSharp d.LoadFrom(ref temp); } } + + /// + /// Convert 'source.Length' values normalized into [0..1] from 'source' + /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. + /// The implementation is SIMD optimized and works only with `source.Length` divisible by 8. + /// Based on: + /// + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// + /// + internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) + { + GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); + + DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 5c0b8ee93a..fd263b54c5 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -52,9 +52,8 @@ namespace SixLabors.ImageSharp } /// - /// A variant of , which is faster on new RyuJIT runtime. + /// Implementation , which is faster on new RyuJIT runtime. /// - // ReSharper disable once MemberHidesStaticFromOuterClass internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue( @@ -116,13 +115,8 @@ namespace SixLabors.ImageSharp } /// - /// A variant of , which is faster on new .NET runtime. + /// Implementation of , which is faster on new .NET runtime. /// - /// - /// It does NOT worth yet to utilize this method (2018 Oct). - /// See benchmark results for the "PackFromVector4_Rgba32" benchmark! - /// TODO: Check again later! - /// internal static void BulkConvertNormalizedFloatToByteClampOverflows( ReadOnlySpan source, Span dest) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 73e9bacfa8..111ac22408 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -22,17 +22,10 @@ namespace SixLabors.ImageSharp public static bool IsAvx2CompatibleArchitecture { get; } = Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; - internal static void GuardAvx2(string operation) - { - if (!IsAvx2CompatibleArchitecture) - { - throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); - } - } - /// /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. /// + /// The vector [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector4 PseudoRound(this Vector4 v) { @@ -48,14 +41,15 @@ namespace SixLabors.ImageSharp /// https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110 /// /// + /// The vector [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector FastRound(this Vector x) + internal static Vector FastRound(this Vector v) { Vector magic0 = new Vector(int.MinValue); // 0x80000000 Vector sgn0 = Vector.AsVectorSingle(magic0); - Vector and0 = Vector.BitwiseAnd(sgn0, x); + Vector and0 = Vector.BitwiseAnd(sgn0, v); Vector or0 = Vector.BitwiseOr(and0, new Vector(8388608.0f)); - Vector add0 = Vector.Add(x, or0); + Vector add0 = Vector.Add(v, or0); Vector sub0 = Vector.Subtract(add0, or0); return sub0; } @@ -65,6 +59,8 @@ namespace SixLabors.ImageSharp /// should be the of the same size as , /// but there are no restrictions on the span's length. /// + /// The source span of bytes + /// The destination span of floats internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); @@ -92,6 +88,8 @@ namespace SixLabors.ImageSharp /// should be the of the same size as , /// but there are no restrictions on the span's length. /// + /// The source span of floats + /// The destination span of bytes internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); @@ -119,5 +117,13 @@ namespace SixLabors.ImageSharp } } } + + private static void GuardAvx2(string operation) + { + if (!IsAvx2CompatibleArchitecture) + { + throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); + } + } } } \ No newline at end of file From d1d52a713336fd3e411777044cdbd474c245a3b8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 17:29:34 +0200 Subject: [PATCH 039/238] FallbackIntrinsics128 + ImageMaths.Modulo* implementations --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 16 ++ .../Helpers/SimdUtils.BasicIntrinsics256.cs | 2 +- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 5 +- .../SimdUtils.FallbackIntrinsics128.cs | 143 ++++++++++++++++++ src/ImageSharp/Common/Helpers/SimdUtils.cs | 6 +- .../Color/Bulk/PackFromVector4.cs | 26 +--- .../Color/Bulk/ToVector4.cs | 25 +-- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 27 +++- .../Helpers/ImageMathsTests.cs | 54 +++++++ 9 files changed, 256 insertions(+), 48 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 35769d96a7..e4fd9bce60 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -39,6 +39,22 @@ namespace SixLabors.ImageSharp return (a / GreatestCommonDivisor(a, b)) * b; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Modulo4(int a) => a & 3; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Modulo8(int a) => a & 7; + + /// + /// Fast (mod m) calculator, + /// where should be a power of 2. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ModuloP2(int a, int m) + { + return a & (m - 1); + } + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index a8b3434980..c7fd21a8f0 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp internal static partial class SimdUtils { /// - /// 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*) + /// Implementation with 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen etc.) /// public static class BasicIntrinsics256 { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index fd263b54c5..996a08fb4b 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -10,8 +10,9 @@ namespace SixLabors.ImageSharp internal static partial class SimdUtils { /// - /// Methods accelerated only in RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) - /// PR: + /// Implementation methods based on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*). + /// Only accelerated only on RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) + /// See: /// https://github.com/dotnet/coreclr/pull/10662 /// API Proposal: /// https://github.com/dotnet/corefx/issues/15957 diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs new file mode 100644 index 0000000000..bb21474660 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -0,0 +1,143 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Fallback implementation based on (128bit). + /// For , efficient software fallback implementations are present + /// + maybe even mono can emit intrinsics for that type :P + /// + public static class FallbackIntrinsics128 + { + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + int remainder = source.Length % 4; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, alignedCount), + dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + + /// + /// as much elements as possible, slicing them down (keeping the remainder). + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + int remainder = source.Length % 4; + int alignedCount = source.Length - remainder; + + if (alignedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows( + source.Slice(0, alignedCount), + dest.Slice(0, alignedCount)); + + source = source.Slice(alignedCount); + dest = dest.Slice(alignedCount); + } + } + + /// + /// Implementation of using . + /// + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + DebugGuard.IsTrue((dest.Length % 4) == 0, nameof(dest), "dest.Length should be divisible by 4!"); + + int count = dest.Length / 4; + if (count == 0) + { + return; + } + + ref ByteVector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Vector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + const float Scale = 1f / 255f; + Vector4 d = default; + + for (int i = 0; i < count; i++) + { + ref ByteVector4 s = ref Unsafe.Add(ref sBase, i); + d.X = s.X; + d.Y = s.Y; + d.Z = s.Z; + d.W = s.W; + d *= Scale; + Unsafe.Add(ref dBase, i) = d; + } + } + + /// + /// Implementation of using . + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflows( + ReadOnlySpan source, + Span dest) + { + DebugGuard.IsTrue((source.Length % 4) == 0, nameof(source), "source.Length should be divisible by 4!"); + + int count = source.Length / 4; + if (count == 0) + { + return; + } + + ref Vector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref ByteVector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + var half = new Vector4(0.5f); + var maxBytes = new Vector4(255f); + + for (int i = 0; i < count; i++) + { + Vector4 s = Unsafe.Add(ref sBase, i); + s *= maxBytes; + s += half; + + // I'm not sure if Clamp() is properly implemented with intrinsics. + s = Vector4.Max(Vector4.Zero, s); + s = Vector4.Min(maxBytes, s); + + ref ByteVector4 d = ref Unsafe.Add(ref dBase, i); + d.X = (byte)s.X; + d.Y = (byte)s.Y; + d.Z = (byte)s.Z; + d.W = (byte)s.W; + } + } + + [StructLayout(LayoutKind.Sequential)] + private struct ByteVector4 + { + public byte X; + public byte Y; + public byte Z; + public byte W; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 111ac22408..bc75dc8caa 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp } /// - /// Converts `dest.Length` -s to -s normalized into [0..1]. + /// Converts all input -s to -s normalized into [0..1]. /// should be the of the same size as , /// but there are no restrictions on the span's length. /// @@ -67,6 +67,7 @@ namespace SixLabors.ImageSharp ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); + FallbackIntrinsics128.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); // Deal with the remainder: int count = source.Length; @@ -83,7 +84,7 @@ namespace SixLabors.ImageSharp } /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of . + /// Convert all values normalized into [0..1] from 'source' into 'dest' buffer of . /// The values are scaled up into [0-255] and rounded, overflows are clamped. /// should be the of the same size as , /// but there are no restrictions on the span's length. @@ -96,6 +97,7 @@ namespace SixLabors.ImageSharp ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); // Deal with the remainder: int count = source.Length; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index 7a212b0523..a56082fcd3 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -72,30 +72,16 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class PackFromVector4_Rgba32 : PackFromVector4 { [Benchmark] - public void BasicBulk() + public void FallbackIntrinsics128() { - ref Vector4 sBase = ref this.source.GetSpan()[0]; - ref Rgba32 dBase = ref this.destination.GetSpan()[0]; - - Vector4 maxBytes = new Vector4(255); - Vector4 half = new Vector4(0.5f); + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - for (int i = 0; i < this.Count; i++) - { - Vector4 v = Unsafe.Add(ref sBase, i); - v *= maxBytes; - v += half; - v = Vector4.Clamp(v, Vector4.Zero, maxBytes); - ref Rgba32 d = ref Unsafe.Add(ref dBase, i); - d.R = (byte)v.X; - d.G = (byte)v.Y; - d.B = (byte)v.Z; - d.A = (byte)v.W; - } + SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } [Benchmark(Baseline = true)] - public void BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows() + public void BasicIntrinsics256() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); @@ -104,7 +90,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows() + public void ExtendedIntrinsic() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 4a801d64ef..519edaa31f 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -79,29 +79,16 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public class ToVector4_Rgba32 : ToVector4 { [Benchmark] - public void BasicBulk() + public void FallbackIntrinsics128() { - ref Rgba32 sBase = ref this.source.GetSpan()[0]; - ref Vector4 dBase = ref this.destination.GetSpan()[0]; - - Vector4 scale = new Vector4(1f / 255f); - - Vector4 v = default; + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - for (int i = 0; i < this.Count; i++) - { - ref Rgba32 s = ref Unsafe.Add(ref sBase, i); - v.X = s.R; - v.Y = s.G; - v.Z = s.B; - v.W = s.A; - v *= scale; - Unsafe.Add(ref dBase, i) = v; - } + SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } [Benchmark(Baseline = true)] - public void BasicIntrinsics256_BulkConvertByteToNormalizedFloat() + public void BasicIntrinsics256() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); @@ -110,7 +97,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat() + public void ExtendedIntrinsics() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 2dcba2b74b..feefd17580 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BasicIntrinsics_BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BasicIntrinsics_BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -161,6 +161,7 @@ namespace SixLabors.ImageSharp.Tests.Common } public static readonly TheoryData ArraySizesDivisibleBy8 = new TheoryData { 0, 8, 16, 1024 }; + public static readonly TheoryData ArraySizesDivisibleBy4 = new TheoryData { 0, 4, 8, 28, 1020 }; public static readonly TheoryData ArraySizesDivisibleBy32 = new TheoryData { 0, 32, 512 }; @@ -170,9 +171,18 @@ namespace SixLabors.ImageSharp.Tests.Common 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 520, }; + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy4))] + public void FallbackIntrinsics128_BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + [Theory] [MemberData(nameof(ArraySizesDivisibleBy8))] - public void BasicIntrinsics_BulkConvertByteToNormalizedFloat(int count) + public void BasicIntrinsics256_BulkConvertByteToNormalizedFloat(int count) { if (this.SkipOnNonAvx2()) { @@ -215,9 +225,18 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy4))] + public void FallbackIntrinsics128_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + [Theory] [MemberData(nameof(ArraySizesDivisibleBy8))] - public void BasicIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows(int count) { if (this.SkipOnNonAvx2()) { diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 6c2979fe9e..aec4d0b810 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -9,6 +9,60 @@ namespace SixLabors.ImageSharp.Tests.Helpers public class ImageMathsTests { + [Theory] + [InlineData(0, 0)] + [InlineData(1, 1)] + [InlineData(2, 2)] + [InlineData(3, 3)] + [InlineData(4, 0)] + [InlineData(100, 0)] + [InlineData(123, 3)] + [InlineData(53436353, 1)] + public void Modulo4(int a, int expected) + { + int actual = ImageMaths.Modulo4(a); + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0, 0)] + [InlineData(1, 1)] + [InlineData(2, 2)] + [InlineData(6, 6)] + [InlineData(7, 7)] + [InlineData(8, 0)] + [InlineData(100, 4)] + [InlineData(123, 3)] + [InlineData(53436353, 1)] + [InlineData(975, 7)] + public void Modulo8(int a, int expected) + { + int actual = ImageMaths.Modulo8(a); + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0, 2, 0)] + [InlineData(1, 2, 1)] + [InlineData(2, 2, 0)] + [InlineData(0, 4, 0)] + [InlineData(3, 4, 3)] + [InlineData(5, 4, 1)] + [InlineData(5, 8, 5)] + [InlineData(8, 8, 0)] + [InlineData(8, 16, 8)] + [InlineData(15, 16, 15)] + [InlineData(17, 16, 1)] + [InlineData(17, 32, 17)] + [InlineData(31, 32, 31)] + [InlineData(32, 32, 0)] + [InlineData(33, 32, 1)] + public void Modulo2P(int a, int m, int expected) + { + int actual = ImageMaths.ModuloP2(a, m); + Assert.Equal(expected, actual); + } + [Fact] public void FasAbsResultMatchesMath() { From bf7c9338960aa5d6846d6062c107e2305c518609 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 21:00:15 +0200 Subject: [PATCH 040/238] minimize ceremonial overhead in BulkConvertByteToNormalizedFloat() and BulkConvertNormalizedFloatToByteClampOverflows() --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 45 +++++---- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 91 ++++++++++-------- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 96 ++++++++++--------- .../SimdUtils.FallbackIntrinsics128.cs | 56 +++++++---- src/ImageSharp/Common/Helpers/SimdUtils.cs | 84 +++++++++++----- .../Color/Bulk/PackFromVector4.cs | 50 +++++----- .../Color/Bulk/ToVector4.cs | 50 +++++----- .../General/{ => BasicMath}/Abs.cs | 8 +- .../General/{ => BasicMath}/Clamp.cs | 10 +- .../BasicMath/ModuloPowerOfTwoConstant.cs | 23 +++++ .../BasicMath/ModuloPowerOfTwoVariable.cs | 32 +++++++ .../General/{ => BasicMath}/Pow.cs | 3 +- .../ImageSharp.Benchmarks/General/Modulus.cs | 19 ---- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 17 +++- .../Helpers/ImageMathsTests.cs | 94 ++++++++++-------- 15 files changed, 406 insertions(+), 272 deletions(-) rename tests/ImageSharp.Benchmarks/General/{ => BasicMath}/Abs.cs (88%) rename tests/ImageSharp.Benchmarks/General/{ => BasicMath}/Clamp.cs (94%) create mode 100644 tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs create mode 100644 tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs rename tests/ImageSharp.Benchmarks/General/{ => BasicMath}/Pow.cs (93%) delete mode 100644 tests/ImageSharp.Benchmarks/General/Modulus.cs diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index e4fd9bce60..1395975ec8 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -39,22 +39,31 @@ namespace SixLabors.ImageSharp return (a / GreatestCommonDivisor(a, b)) * b; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Modulo4(int a) => a & 3; + /// + /// Calculates % 4 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int Modulo4(int x) => x & 3; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Modulo8(int a) => a & 7; + /// + /// Calculates % 8 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int Modulo8(int x) => x & 7; /// - /// Fast (mod m) calculator, - /// where should be a power of 2. + /// Fast (x mod m) calculator, with the restriction that + /// should be power of 2. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int ModuloP2(int a, int m) + [MethodImpl(InliningOptions.ShortMethod)] + public static int ModuloP2(int x, int m) { - return a & (m - 1); + return x & (m - 1); } + [MethodImpl(InliningOptions.ShortMethod)] + public static float Clamp(float x, float min, float max) => Math.Min(max, Math.Max(min, x)); + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// @@ -62,7 +71,7 @@ namespace SixLabors.ImageSharp /// A number that is greater than , but less than or equal to /// /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int FastAbs(int x) { int y = x >> 31; @@ -74,7 +83,7 @@ namespace SixLabors.ImageSharp /// /// A single-precision floating-point number /// The number raised to the power of 2. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Pow2(float x) => x * x; /// @@ -82,7 +91,7 @@ namespace SixLabors.ImageSharp /// /// A single-precision floating-point number /// The number raised to the power of 3. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Pow3(float x) => x * x * x; /// @@ -93,7 +102,7 @@ namespace SixLabors.ImageSharp /// /// The /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int GetBitsNeededForColorDepth(int colors) => Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2))); /// @@ -101,7 +110,7 @@ namespace SixLabors.ImageSharp /// /// The bit depth. /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int GetColorCountForBitDepth(int bitDepth) => 1 << bitDepth; /// @@ -110,7 +119,7 @@ namespace SixLabors.ImageSharp /// The x provided to G(x). /// The spread of the blur. /// The Gaussian G(x) - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Gaussian(float x, float sigma) { const float Numerator = 1.0f; @@ -133,7 +142,7 @@ namespace SixLabors.ImageSharp /// /// The sine cardinal of . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float SinC(float f) { if (MathF.Abs(f) > Constants.Epsilon) @@ -156,7 +165,7 @@ namespace SixLabors.ImageSharp /// /// The . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float GetBcValue(float x, float b, float c) { if (x < 0F) @@ -192,7 +201,7 @@ namespace SixLabors.ImageSharp /// /// The bounding . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) => new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); /// diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index c7fd21a8f0..713d606e79 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -21,28 +21,58 @@ namespace SixLabors.ImageSharp public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture; /// - /// as much elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloatReduce( ref ReadOnlySpan source, ref Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - if (IsAvailable) + if (!IsAvailable) { - int remainder = source.Length % 8; - int alignedCount = source.Length - remainder; - - if (alignedCount > 0) - { - BulkConvertByteToNormalizedFloat( - source.Slice(0, alignedCount), - dest.Slice(0, alignedCount)); - - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); - } + return; + } + + int remainder = ImageMaths.Modulo8(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.Modulo8(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); } } @@ -57,7 +87,7 @@ namespace SixLabors.ImageSharp { GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); - DebugGuard.IsTrue((dest.Length % 8) == 0, nameof(source), "dest.Length should be divisable by 8!"); + DebugGuard.IsTrue(ImageMaths.Modulo8(dest.Length) == 0, nameof(source), "dest.Length should be divisable by 8!"); var bVec = new Vector(256.0f / 255.0f); var magicFloat = new Vector(32768.0f); @@ -93,30 +123,6 @@ namespace SixLabors.ImageSharp } } - /// - /// as much elements as possible, slicing them down (keeping the remainder). - /// - internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - - if (IsAvailable) - { - int remainder = source.Length % Vector.Count; - int alignedCount = source.Length - remainder; - - if (alignedCount > 0) - { - BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); - - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); - } - } - } - /// /// Implementation of which is faster on older runtimes. /// @@ -124,7 +130,7 @@ namespace SixLabors.ImageSharp { GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); - DebugGuard.IsTrue((source.Length % 8) == 0, nameof(source), "source.Length should be divisible by 8!"); + DebugGuard.IsTrue(ImageMaths.Modulo8(source.Length) == 0, nameof(source), "source.Length should be divisible by 8!"); if (source.Length == 0) { @@ -174,7 +180,10 @@ namespace SixLabors.ImageSharp { GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); + DebugGuard.IsTrue( + ImageMaths.Modulo8(source.Length) == 0, + nameof(source), + "source.Length should be divisible by 8!"); if (source.Length == 0) { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 996a08fb4b..dfa6f189c8 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -28,27 +28,58 @@ namespace SixLabors.ImageSharp #endif /// - /// as much elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// - [Conditional("NETCOREAPP2_1")] + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloatReduce( ref ReadOnlySpan source, ref Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - if (IsAvailable) + if (!IsAvailable) { - int remainder = source.Length % Vector.Count; - int alignedCount = source.Length - remainder; + return; + } + + int remainder = ImageMaths.ModuloP2(source.Length, Vector.Count); + int adjustedCount = source.Length - remainder; - if (alignedCount > 0) - { - BulkConvertByteToNormalizedFloat(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); - } + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.ModuloP2(source.Length, Vector.Count); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); } } @@ -58,7 +89,7 @@ namespace SixLabors.ImageSharp internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue( - dest.Length % Vector.Count == 0, + ImageMaths.ModuloP2(dest.Length, Vector.Count) == 0, nameof(source), "dest.Length should be divisible by Vector.Count!"); @@ -67,8 +98,6 @@ namespace SixLabors.ImageSharp ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - var scale = new Vector(1f / 255f); - for (int i = 0; i < n; i++) { Vector b = Unsafe.Add(ref sourceBase, i); @@ -77,10 +106,10 @@ namespace SixLabors.ImageSharp Vector.Widen(s0, out Vector w0, out Vector w1); Vector.Widen(s1, out Vector w2, out Vector w3); - Vector f0 = ConvertToSingle(w0, scale); - Vector f1 = ConvertToSingle(w1, scale); - Vector f2 = ConvertToSingle(w2, scale); - Vector f3 = ConvertToSingle(w3, scale); + Vector f0 = ConvertToSingle(w0); + Vector f1 = ConvertToSingle(w1); + Vector f2 = ConvertToSingle(w2); + Vector f3 = ConvertToSingle(w3); ref Vector d = ref Unsafe.Add(ref destBase, i * 4); d = f0; @@ -90,31 +119,6 @@ namespace SixLabors.ImageSharp } } - /// - /// as much elements as possible, slicing them down (keeping the remainder). - /// - [Conditional("NETCOREAPP2_1")] - internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - - if (IsAvailable) - { - int remainder = source.Length % Vector.Count; - int alignedCount = source.Length - remainder; - - if (alignedCount > 0) - { - BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, alignedCount), dest.Slice(0, alignedCount)); - - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); - } - } - } - /// /// Implementation of , which is faster on new .NET runtime. /// @@ -123,7 +127,7 @@ namespace SixLabors.ImageSharp Span dest) { DebugGuard.IsTrue( - dest.Length % Vector.Count == 0, + ImageMaths.ModuloP2(dest.Length, Vector.Count) == 0, nameof(dest), "dest.Length should be divisible by Vector.Count!"); @@ -168,11 +172,11 @@ namespace SixLabors.ImageSharp } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToSingle(Vector u, Vector scale) + private static Vector ConvertToSingle(Vector u) { Vector vi = Vector.AsVectorInt32(u); Vector v = Vector.ConvertToSingle(vi); - v *= scale; + v *= new Vector(1f / 255f); return v; } } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index bb21474660..2d9f53eafa 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -1,71 +1,81 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +// ReSharper disable MemberHidesStaticFromOuterClass namespace SixLabors.ImageSharp { internal static partial class SimdUtils { /// /// Fallback implementation based on (128bit). - /// For , efficient software fallback implementations are present - /// + maybe even mono can emit intrinsics for that type :P + /// For , efficient software fallback implementations are present, + /// and we hope that even mono's JIT is able to emit SIMD instructions for that type :P /// public static class FallbackIntrinsics128 { /// - /// as much elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloatReduce( ref ReadOnlySpan source, ref Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - int remainder = source.Length % 4; - int alignedCount = source.Length - remainder; + int remainder = ImageMaths.Modulo4(source.Length); + int adjustedCount = source.Length - remainder; - if (alignedCount > 0) + if (adjustedCount > 0) { BulkConvertByteToNormalizedFloat( - source.Slice(0, alignedCount), - dest.Slice(0, alignedCount)); + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); } } /// - /// as much elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( ref ReadOnlySpan source, ref Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); - int remainder = source.Length % 4; - int alignedCount = source.Length - remainder; + int remainder = ImageMaths.Modulo4(source.Length); + int adjustedCount = source.Length - remainder; - if (alignedCount > 0) + if (adjustedCount > 0) { BulkConvertNormalizedFloatToByteClampOverflows( - source.Slice(0, alignedCount), - dest.Slice(0, alignedCount)); + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); - source = source.Slice(alignedCount); - dest = dest.Slice(alignedCount); + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); } } /// /// Implementation of using . /// + [MethodImpl(InliningOptions.ColdPath)] internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue((dest.Length % 4) == 0, nameof(dest), "dest.Length should be divisible by 4!"); + DebugGuard.IsTrue( + ImageMaths.Modulo4(dest.Length) == 0, + nameof(dest), + "dest.Length should be divisible by 4!"); int count = dest.Length / 4; if (count == 0) @@ -94,11 +104,15 @@ namespace SixLabors.ImageSharp /// /// Implementation of using . /// + [MethodImpl(InliningOptions.ColdPath)] internal static void BulkConvertNormalizedFloatToByteClampOverflows( ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue((source.Length % 4) == 0, nameof(source), "source.Length should be divisible by 4!"); + DebugGuard.IsTrue( + ImageMaths.Modulo4(source.Length) == 0, + nameof(source), + "source.Length should be divisible by 4!"); int count = source.Length / 4; if (count == 0) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index bc75dc8caa..95a6030fd1 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -61,25 +62,22 @@ namespace SixLabors.ImageSharp /// /// The source span of bytes /// The destination span of floats + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); +#if NETCOREAPP2_1 ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); +#else BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); +#endif FallbackIntrinsics128.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); // Deal with the remainder: - int count = source.Length; - if (count > 0) + if (source.Length > 0) { - // TODO: Do we need to optimize anything on this? (There are at most 7 remainders) - ref byte sBase = ref MemoryMarshal.GetReference(source); - ref float dBase = ref MemoryMarshal.GetReference(dest); - for (int i = 0; i < count; i++) - { - Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i) / 255f; - } + ConverByteToNormalizedFloatRemainder(source, dest); } } @@ -91,35 +89,71 @@ namespace SixLabors.ImageSharp /// /// The source span of floats /// The destination span of bytes + [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); +#if NETCOREAPP2_1 ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); +#else BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); +#endif FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); // Deal with the remainder: - int count = source.Length; - if (count > 0) + if (source.Length > 0) { - ref float sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - // TODO: Do we need to optimize anything on this? (There are at most 7 remainders) - float f = Unsafe.Add(ref sBase, i); - f *= 255f; - f += 0.5f; - f = MathF.Max(0, f); - f = MathF.Min(255f, f); - - Unsafe.Add(ref dBase, i) = (byte)f; - } + ConvertNormalizedFloatToByteRemainder(source, dest); } } + [MethodImpl(InliningOptions.ColdPath)] + private static void ConverByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) + { + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref float dBase = ref MemoryMarshal.GetReference(dest); + + // There are at most 3 elements at this point, having a for loop is overkill. + // Let's minimize the no. of instructions! + switch (source.Length) + { + case 3: + Unsafe.Add(ref dBase, 2) = Unsafe.Add(ref sBase, 2) / 255f; + goto case 2; + case 2: + Unsafe.Add(ref dBase, 1) = Unsafe.Add(ref sBase, 1) / 255f; + goto case 1; + case 1: + dBase = sBase / 255f; + break; + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span dest) + { + ref float sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(dest); + + switch (source.Length) + { + case 3: + Unsafe.Add(ref dBase, 2) = ConvertToByte(Unsafe.Add(ref sBase, 2)); + goto case 2; + case 2: + Unsafe.Add(ref dBase, 1) = ConvertToByte(Unsafe.Add(ref sBase, 1)); + goto case 1; + case 1: + dBase = ConvertToByte(sBase); + break; + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static byte ConvertToByte(float f) => (byte)ImageMaths.Clamp((f * 255f) + 0.5f, 0, 255f); + + [Conditional("DEBUG")] private static void GuardAvx2(string operation) { if (!IsAvx2CompatibleArchitecture) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index a56082fcd3..eaa52a9750 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -99,30 +99,30 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } // RESULTS (2018 October): - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ------------------------------------------------------------------ |-------- |------ |-------------:|-------------:|-----------:|-------:|---------:|-------:|----------:| - // BasicBulk | Clr | 64 | 581.62 ns | 33.625 ns | 1.8999 ns | 2.27 | 0.02 | - | 0 B | - // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 64 | 256.66 ns | 45.153 ns | 2.5512 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 64 | 201.92 ns | 30.161 ns | 1.7042 ns | 0.79 | 0.01 | - | 0 B | - // PixelOperations_Base | Clr | 64 | 665.01 ns | 13.032 ns | 0.7363 ns | 2.59 | 0.02 | 0.0067 | 24 B | - // PixelOperations_Specialized | Clr | 64 | 295.14 ns | 26.335 ns | 1.4880 ns | 1.15 | 0.01 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Core | 64 | 513.22 ns | 91.110 ns | 5.1479 ns | 3.19 | 0.03 | - | 0 B | - // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Core | 64 | 160.76 ns | 2.760 ns | 0.1559 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 64 | 95.98 ns | 10.077 ns | 0.5694 ns | 0.60 | 0.00 | - | 0 B | - // PixelOperations_Base | Core | 64 | 591.74 ns | 49.856 ns | 2.8170 ns | 3.68 | 0.01 | 0.0067 | 24 B | - // PixelOperations_Specialized | Core | 64 | 149.11 ns | 4.485 ns | 0.2534 ns | 0.93 | 0.00 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Clr | 2048 | 15,345.85 ns | 1,213.551 ns | 68.5679 ns | 3.90 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 3,939.49 ns | 71.101 ns | 4.0173 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Clr | 2048 | 2,272.61 ns | 110.671 ns | 6.2531 ns | 0.58 | 0.00 | - | 0 B | - // PixelOperations_Base | Clr | 2048 | 17,422.47 ns | 811.733 ns | 45.8644 ns | 4.42 | 0.01 | - | 24 B | - // PixelOperations_Specialized | Clr | 2048 | 3,984.26 ns | 110.352 ns | 6.2351 ns | 1.01 | 0.00 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Core | 2048 | 14,950.43 ns | 699.309 ns | 39.5123 ns | 3.76 | 0.02 | - | 0 B | - // BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 3,978.28 ns | 481.105 ns | 27.1833 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic_BulkConvertNormalizedFloatToByteClampOverflows | Core | 2048 | 2,169.54 ns | 75.606 ns | 4.2719 ns | !!0.55!| 0.00 | - | 0 B | - // PixelOperations_Base | Core | 2048 | 18,403.62 ns | 1,494.056 ns | 84.4169 ns | 4.63 | 0.03 | - | 24 B | - // PixelOperations_Specialized | Core | 2048 | 2,227.60 ns | 486.761 ns | 27.5029 ns | !!0.56!| 0.01 | - | 0 B | + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |-------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 340.38 ns | 22.319 ns | 1.2611 ns | 1.41 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.79 ns | 11.421 ns | 0.6453 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Clr | 64 | 199.09 ns | 124.239 ns | 7.0198 ns | 0.83 | 0.02 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 647.99 ns | 24.003 ns | 1.3562 ns | 2.69 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 259.79 ns | 13.391 ns | 0.7566 ns | 1.08 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 234.64 ns | 12.320 ns | 0.6961 ns | 1.58 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 148.87 ns | 2.794 ns | 0.1579 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Core | 64 | 94.06 ns | 10.015 ns | 0.5659 ns | 0.63 | 0.00 | - | 0 B | + // PixelOperations_Base | Core | 64 | 573.52 ns | 31.865 ns | 1.8004 ns | 3.85 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 64 | 117.21 ns | 13.264 ns | 0.7494 ns | 0.79 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 6,735.93 ns | 2,139.340 ns | 120.8767 ns | 1.71 | 0.03 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 3,929.29 ns | 334.027 ns | 18.8731 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Clr | 2048 | 2,226.01 ns | 130.525 ns | 7.3749 ns |!! 0.57 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 16,760.84 ns | 367.800 ns | 20.7814 ns | 4.27 | 0.02 | - | 24 B | <--- Extra copies using "Vector4 TPixel.ToVector4()" + // PixelOperations_Specialized | Clr | 2048 | 3,986.03 ns | 237.238 ns | 13.4044 ns | 1.01 | 0.00 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 6,644.65 ns | 2,677.090 ns | 151.2605 ns | 1.69 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 3,923.70 ns | 1,971.760 ns | 111.4081 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Core | 2048 | 2,092.32 ns | 375.657 ns | 21.2253 ns |!! 0.53 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 16,875.73 ns | 1,271.957 ns | 71.8679 ns | 4.30 | 0.10 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,129.92 ns | 262.888 ns | 14.8537 ns |!! 0.54 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 519edaa31f..2cbe549e4a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -191,30 +191,30 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk // RESULTS (2018 October): // - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ---------------------------------------------------- |-------- |------ |------------:|-------------:|-----------:|-------:|---------:|-------:|----------:| - // BasicBulk | Clr | 64 | 267.40 ns | 30.711 ns | 1.7352 ns | 1.07 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Clr | 64 | 249.97 ns | 33.838 ns | 1.9119 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Clr | 64 | 176.97 ns | 5.221 ns | 0.2950 ns | 0.71 | 0.00 | - | 0 B | - // PixelOperations_Base | Clr | 64 | 349.70 ns | 104.331 ns | 5.8949 ns | 1.40 | 0.02 | 0.0072 | 24 B | - // PixelOperations_Specialized | Clr | 64 | 288.31 ns | 26.833 ns | 1.5161 ns | 1.15 | 0.01 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Core | 64 | 185.36 ns | 30.051 ns | 1.6979 ns | 1.26 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Core | 64 | 146.84 ns | 12.674 ns | 0.7161 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Core | 64 | 67.31 ns | 2.542 ns | 0.1436 ns | 0.46 | 0.00 | - | 0 B | - // PixelOperations_Base | Core | 64 | 272.03 ns | 94.419 ns | 5.3348 ns | 1.85 | 0.03 | 0.0072 | 24 B | - // PixelOperations_Specialized | Core | 64 | 121.91 ns | 31.477 ns | 1.7785 ns | 0.83 | 0.01 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Clr | 2048 | 5,133.04 ns | 284.052 ns | 16.0494 ns | 1.21 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Clr | 2048 | 4,248.58 ns | 1,095.887 ns | 61.9196 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Clr | 2048 | 1,214.02 ns | 184.349 ns | 10.4160 ns | 0.29 | 0.00 | - | 0 B | - // PixelOperations_Base | Clr | 2048 | 7,096.04 ns | 362.350 ns | 20.4734 ns | 1.67 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Clr | 2048 | 4,314.19 ns | 204.964 ns | 11.5809 ns | 1.02 | 0.01 | - | 0 B | - // | | | | | | | | | | - // BasicBulk | Core | 2048 | 5,038.38 ns | 223.282 ns | 12.6158 ns | 1.20 | 0.01 | - | 0 B | - // BasicIntrinsics256_BulkConvertByteToNormalizedFloat | Core | 2048 | 4,199.17 ns | 897.985 ns | 50.7378 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics_BulkConvertByteToNormalizedFloat | Core | 2048 | 1,113.86 ns | 64.799 ns | 3.6613 ns | !!0.27!| 0.00 | - | 0 B | - // PixelOperations_Base | Core | 2048 | 7,015.00 ns | 920.083 ns | 51.9864 ns | 1.67 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Core | 2048 | 1,176.59 ns | 256.955 ns | 14.5184 ns | !!0.28!| 0.00 | - | 0 B | + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | + // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Abs.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs similarity index 88% rename from tests/ImageSharp.Benchmarks/General/Abs.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs index a67f3f1078..ea53959b6a 100644 --- a/tests/ImageSharp.Benchmarks/General/Abs.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs @@ -1,9 +1,9 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; +using System; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ public class Abs { [Params(-1, 1)] diff --git a/tests/ImageSharp.Benchmarks/General/Clamp.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/General/Clamp.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs index ef6bc3c402..d486cb2f37 100644 --- a/tests/ImageSharp.Benchmarks/General/Clamp.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs @@ -3,13 +3,13 @@ // Licensed under the Apache License, Version 2.0. // -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; - using System.Runtime.CompilerServices; +using System; +using System.Runtime.CompilerServices; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ public class Clamp { [Params(-1, 0, 255, 256)] diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs new file mode 100644 index 0000000000..9ddfad7222 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs @@ -0,0 +1,23 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + [LongRunJob] + public class ModuloPowerOfTwoConstant + { + private readonly int value = 42; + + [Benchmark(Baseline = true)] + public int Standard() + { + return this.value % 8; + } + + [Benchmark] + public int Bitwise() + { + return ImageMaths.Modulo8(this.value); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs new file mode 100644 index 0000000000..5c2fe81fa2 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs @@ -0,0 +1,32 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + [LongRunJob] + public class ModuloPowerOfTwoVariable + { + private readonly int value = 42; + + private readonly int m = 32; + + [Benchmark(Baseline = true)] + public int Standard() + { + return this.value % this.m; + } + + [Benchmark] + public int Bitwise() + { + return ImageMaths.ModuloP2(this.value, this.m); + } + + // RESULTS: + // + // Method | Mean | Error | StdDev | Median | Scaled | ScaledSD | + // --------- |----------:|----------:|----------:|----------:|-------:|---------:| + // Standard | 1.2465 ns | 0.0093 ns | 0.0455 ns | 1.2423 ns | 1.00 | 0.00 | + // Bitwise | 0.0265 ns | 0.0103 ns | 0.0515 ns | 0.0000 ns | 0.02 | 0.04 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Pow.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs similarity index 93% rename from tests/ImageSharp.Benchmarks/General/Pow.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs index 325bd9d20e..0f256fc781 100644 --- a/tests/ImageSharp.Benchmarks/General/Pow.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs @@ -1,7 +1,8 @@ using System; + using BenchmarkDotNet.Attributes; -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath { public class Pow { diff --git a/tests/ImageSharp.Benchmarks/General/Modulus.cs b/tests/ImageSharp.Benchmarks/General/Modulus.cs deleted file mode 100644 index e6d5ccce62..0000000000 --- a/tests/ImageSharp.Benchmarks/General/Modulus.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using BenchmarkDotNet.Attributes; - - public class Modulus - { - [Benchmark(Baseline = true, Description = "Standard Modulus using %")] - public int StandardModulus() - { - return 255 % 256; - } - - [Benchmark(Description = "Bitwise Modulus using &")] - public int BitwiseModulus() - { - return 255 & 255; - } - } -} diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index feefd17580..c63cb3438f 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -264,13 +264,26 @@ namespace SixLabors.ImageSharp.Tests.Common TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) ); + + // for small values, let's stress test the implementation a bit: + if (count > 0 && count < 10) + { + for (int i = 0; i < 20; i++) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( + count, + (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span), + i + 42); + } + } } private static void TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( int count, - Action, Memory> convert) + Action, Memory> convert, int seed = -1) { - float[] source = new Random(count).GenerateRandomFloatArray(count, -0.1f, 1.2f); + seed = seed > 0 ? seed : count; + float[] source = new Random(seed).GenerateRandomFloatArray(count, -0.2f, 1.2f); byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); byte[] actual = new byte[count]; diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index aec4d0b810..d8b1525bed 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -10,56 +10,70 @@ namespace SixLabors.ImageSharp.Tests.Helpers public class ImageMathsTests { [Theory] - [InlineData(0, 0)] - [InlineData(1, 1)] - [InlineData(2, 2)] - [InlineData(3, 3)] - [InlineData(4, 0)] - [InlineData(100, 0)] - [InlineData(123, 3)] - [InlineData(53436353, 1)] - public void Modulo4(int a, int expected) + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + [InlineData(3)] + [InlineData(4)] + [InlineData(100)] + [InlineData(123)] + [InlineData(53436353)] + public void Modulo4(int x) { - int actual = ImageMaths.Modulo4(a); - Assert.Equal(expected, actual); + int actual = ImageMaths.Modulo4(x); + Assert.Equal(x % 4, actual); } [Theory] - [InlineData(0, 0)] - [InlineData(1, 1)] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + [InlineData(6)] + [InlineData(7)] + [InlineData(8)] + [InlineData(100)] + [InlineData(123)] + [InlineData(53436353)] + [InlineData(975)] + public void Modulo8(int x) + { + int actual = ImageMaths.Modulo8(x); + Assert.Equal(x % 8, actual); + } + + [Theory] + [InlineData(0, 2)] + [InlineData(1, 2)] [InlineData(2, 2)] - [InlineData(6, 6)] - [InlineData(7, 7)] - [InlineData(8, 0)] - [InlineData(100, 4)] - [InlineData(123, 3)] - [InlineData(53436353, 1)] - [InlineData(975, 7)] - public void Modulo8(int a, int expected) + [InlineData(0, 4)] + [InlineData(3, 4)] + [InlineData(5, 4)] + [InlineData(5, 8)] + [InlineData(8, 8)] + [InlineData(8, 16)] + [InlineData(15, 16)] + [InlineData(17, 16)] + [InlineData(17, 32)] + [InlineData(31, 32)] + [InlineData(32, 32)] + [InlineData(33, 32)] + public void Modulo2P(int x, int m) { - int actual = ImageMaths.Modulo8(a); - Assert.Equal(expected, actual); + int actual = ImageMaths.ModuloP2(x, m); + Assert.Equal(x % m, actual); } [Theory] - [InlineData(0, 2, 0)] - [InlineData(1, 2, 1)] - [InlineData(2, 2, 0)] - [InlineData(0, 4, 0)] - [InlineData(3, 4, 3)] - [InlineData(5, 4, 1)] - [InlineData(5, 8, 5)] - [InlineData(8, 8, 0)] - [InlineData(8, 16, 8)] - [InlineData(15, 16, 15)] - [InlineData(17, 16, 1)] - [InlineData(17, 32, 17)] - [InlineData(31, 32, 31)] - [InlineData(32, 32, 0)] - [InlineData(33, 32, 1)] - public void Modulo2P(int a, int m, int expected) + [InlineData(0, 0, 0, 0)] + [InlineData(0.5f, 0, 1, 0.5f)] + [InlineData(-0.5f, -0.1f, 10, -0.1f)] + [InlineData(-0.05f, -0.1f, 10, -0.05f)] + [InlineData(9.9f, -0.1f, 10, 9.9f)] + [InlineData(10f, -0.1f, 10, 10f)] + [InlineData(10.1f, -0.1f, 10, 10f)] + public void Clamp(float x, float min, float max, float expected) { - int actual = ImageMaths.ModuloP2(a, m); + float actual = ImageMaths.Clamp(x, min, max); Assert.Equal(expected, actual); } From 520c6fc564c7748f73e9e7e64c483f48f0e2490f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 21:09:40 +0200 Subject: [PATCH 041/238] fix comment --- .../Common/Helpers/SimdUtils.FallbackIntrinsics128.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index 2d9f53eafa..ab18a00679 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp s *= maxBytes; s += half; - // I'm not sure if Clamp() is properly implemented with intrinsics. + // I'm not sure if Vector4.Clamp() is properly implemented with intrinsics. s = Vector4.Max(Vector4.Zero, s); s = Vector4.Min(maxBytes, s); From 5c687fa004e32ff8114c58e309070fc2f4ea2ca5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 21 Oct 2018 23:38:12 +0200 Subject: [PATCH 042/238] address review findings + some more cleanup --- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 28 ++++++++----------- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 14 +++------- .../SimdUtils.FallbackIntrinsics128.cs | 14 +++------- src/ImageSharp/Common/Helpers/SimdUtils.cs | 22 ++++++++++++++- src/ImageSharp/Common/Tuples/Octet.cs | 13 +++++++-- src/ImageSharp/Common/Tuples/Vector4Pair.cs | 10 +++---- .../JpegColorConverter.FromYCbCrSimd.cs | 2 +- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 2 +- .../ColorConverters/JpegColorConverter.cs | 4 +-- .../PixelFormats/PixelOperations{TPixel}.cs | 10 +++---- 10 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index 713d606e79..0f1ce2ab6a 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); if (!IsAvailable) { @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); if (!IsAvailable) { @@ -78,16 +78,15 @@ namespace SixLabors.ImageSharp /// /// SIMD optimized implementation for . - /// Works only with `dest.Length` divisible by 8. + /// Works only with span Length divisible by 8. /// Implementation adapted from: /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions /// http://stackoverflow.com/a/536278 /// internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertByteToNormalizedFloat)); - - DebugGuard.IsTrue(ImageMaths.Modulo8(dest.Length) == 0, nameof(source), "dest.Length should be divisable by 8!"); + VerifyIsAvx2Compatible(nameof(BulkConvertByteToNormalizedFloat)); + VerifySpanInput(source, dest, 8); var bVec = new Vector(256.0f / 255.0f); var magicFloat = new Vector(32768.0f); @@ -128,9 +127,8 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); - - DebugGuard.IsTrue(ImageMaths.Modulo8(source.Length) == 0, nameof(source), "source.Length should be divisible by 8!"); + VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); + VerifySpanInput(source, dest, 8); if (source.Length == 0) { @@ -168,9 +166,9 @@ namespace SixLabors.ImageSharp } /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' + /// Convert all values normalized into [0..1] from 'source' /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. - /// The implementation is SIMD optimized and works only with `source.Length` divisible by 8. + /// This implementation is SIMD optimized and works only when span Length is divisible by 8. /// Based on: /// /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions @@ -178,12 +176,8 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue( - ImageMaths.Modulo8(source.Length) == 0, - nameof(source), - "source.Length should be divisible by 8!"); + VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByte)); + VerifySpanInput(source, dest, 8); if (source.Length == 0) { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index dfa6f189c8..e0d6187dca 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); if (!IsAvailable) { @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); if (!IsAvailable) { @@ -88,10 +88,7 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue( - ImageMaths.ModuloP2(dest.Length, Vector.Count) == 0, - nameof(source), - "dest.Length should be divisible by Vector.Count!"); + VerifySpanInput(source, dest, Vector.Count); int n = dest.Length / Vector.Count; @@ -126,10 +123,7 @@ namespace SixLabors.ImageSharp ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue( - ImageMaths.ModuloP2(dest.Length, Vector.Count) == 0, - nameof(dest), - "dest.Length should be divisible by Vector.Count!"); + VerifySpanInput(source, dest, Vector.Count); int n = dest.Length / Vector.Count; diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index ab18a00679..565ea08f5d 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); int remainder = ImageMaths.Modulo4(source.Length); int adjustedCount = source.Length - remainder; @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp ref ReadOnlySpan source, ref Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); int remainder = ImageMaths.Modulo4(source.Length); int adjustedCount = source.Length - remainder; @@ -72,10 +72,7 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ColdPath)] internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue( - ImageMaths.Modulo4(dest.Length) == 0, - nameof(dest), - "dest.Length should be divisible by 4!"); + VerifySpanInput(source, dest, 4); int count = dest.Length / 4; if (count == 0) @@ -109,10 +106,7 @@ namespace SixLabors.ImageSharp ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue( - ImageMaths.Modulo4(source.Length) == 0, - nameof(source), - "source.Length should be divisible by 4!"); + VerifySpanInput(source, dest, 4); int count = source.Length / 4; if (count == 0) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 95a6030fd1..fade8da799 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -154,12 +154,32 @@ namespace SixLabors.ImageSharp private static byte ConvertToByte(float f) => (byte)ImageMaths.Clamp((f * 255f) + 0.5f, 0, 255f); [Conditional("DEBUG")] - private static void GuardAvx2(string operation) + private static void VerifyIsAvx2Compatible(string operation) { if (!IsAvx2CompatibleArchitecture) { throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); } } + + [Conditional("DEBUG")] + private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue( + ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + nameof(source), + $"length should be divisable by {shouldBeDivisibleBy}!"); + } + + [Conditional("DEBUG")] + private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue( + ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + nameof(source), + $"length should be divisable by {shouldBeDivisibleBy}!"); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Tuples/Octet.cs b/src/ImageSharp/Common/Tuples/Octet.cs index ae01a31217..539b74e324 100644 --- a/src/ImageSharp/Common/Tuples/Octet.cs +++ b/src/ImageSharp/Common/Tuples/Octet.cs @@ -3,8 +3,14 @@ using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Tuples { + /// + /// Contains 8 element value tuples of various types. + /// internal static class Octet { + /// + /// Value tuple of -s + /// [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] public struct OfUInt32 { @@ -34,7 +40,7 @@ namespace SixLabors.ImageSharp.Tuples public override string ToString() { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; + return $"{nameof(Octet)}.{nameof(OfUInt32)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})"; } [MethodImpl(InliningOptions.ShortMethod)] @@ -51,6 +57,9 @@ namespace SixLabors.ImageSharp.Tuples } } + /// + /// Value tuple of -s + /// [StructLayout(LayoutKind.Explicit, Size = 8)] public struct OfByte { @@ -80,7 +89,7 @@ namespace SixLabors.ImageSharp.Tuples public override string ToString() { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; + return $"{nameof(Octet)}.{nameof(OfByte)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})"; } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index 5988b2200b..cae283d628 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -7,6 +7,7 @@ namespace SixLabors.ImageSharp.Tuples /// /// Its faster to process multiple Vector4-s together, so let's pair them! /// On AVX2 this pair should be convertible to of ! + /// TODO: Investigate defining this as union with an Octet.OfSingle type. /// [StructLayout(LayoutKind.Sequential)] internal struct Vector4Pair @@ -15,8 +16,6 @@ namespace SixLabors.ImageSharp.Tuples public Vector4 B; - private static readonly Vector4 Scale = new Vector4(1 / 255f); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MultiplyInplace(float value) { @@ -52,8 +51,9 @@ namespace SixLabors.ImageSharp.Tuples b = b.FastRound(); // Downscale by 1/255 - this.A *= Scale; - this.B *= Scale; + var scale = new Vector4(1 / 255f); + this.A *= scale; + this.B *= scale; } /// @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tuples public override string ToString() { - return $"{this.A}, {this.B}"; + return $"{nameof(Vector4Pair)}({this.A}, {this.B})"; } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index 5c63a478db..1dc72aaf5b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); - destination.Collect(ref r, ref g, ref b); + destination.Pack(ref r, ref g, ref b); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index 3f26cdc907..46644258b1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); - destination.Collect(ref rr, ref gg, ref bb); + destination.Pack(ref rr, ref gg, ref bb); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 293f3bc1f7..456636dc39 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -157,9 +157,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters public Vector4 V0, V1, V2, V3, V4, V5, V6, V7; /// - /// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order. + /// Pack (r0,r1...r7) (g0,g1...g7) (b0,b1...b7) vector values as (r0,g0,b0,1), (r1,g1,b1,1) ... /// - public void Collect(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) + public void Pack(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) { this.V0.X = r.A.X; this.V0.Y = g.A.X; diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index cbf164a71c..6c133191a1 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -30,11 +30,10 @@ namespace SixLabors.ImageSharp.PixelFormats internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { ReadOnlySpan sourceVectors1 = sourceVectors; - Span destinationColors1 = destinationColors; - GuardSpans(sourceVectors1, nameof(sourceVectors1), destinationColors1, nameof(destinationColors1), count); + GuardSpans(sourceVectors1, nameof(sourceVectors1), destinationColors, nameof(destinationColors), count); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors1); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors1); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); for (int i = 0; i < count; i++) { @@ -53,11 +52,10 @@ namespace SixLabors.ImageSharp.PixelFormats internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { ReadOnlySpan sourceColors1 = sourceColors; - Span destinationVectors1 = destinationVectors; - GuardSpans(sourceColors1, nameof(sourceColors1), destinationVectors1, nameof(destinationVectors1), count); + GuardSpans(sourceColors1, nameof(sourceColors1), destinationVectors, nameof(destinationVectors), count); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors1); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors1); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); for (int i = 0; i < count; i++) { From 54ccf05794fb7a80c8a03572ab0f7ae5560d4714 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 00:03:12 +0200 Subject: [PATCH 043/238] drop slow Clamp() implementation --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 3 - src/ImageSharp/Common/Helpers/SimdUtils.cs | 6 +- .../General/BasicMath/ClampFloat.cs | 70 +++++++++++++++++++ .../{Clamp.cs => ClampInt32IntoByte.cs} | 2 +- .../Helpers/ImageMathsTests.cs | 2 +- 5 files changed, 75 insertions(+), 8 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs rename tests/ImageSharp.Benchmarks/General/BasicMath/{Clamp.cs => ClampInt32IntoByte.cs} (98%) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 1395975ec8..02a2e9ee55 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -61,9 +61,6 @@ namespace SixLabors.ImageSharp return x & (m - 1); } - [MethodImpl(InliningOptions.ShortMethod)] - public static float Clamp(float x, float min, float max) => Math.Min(max, Math.Max(min, x)); - /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index fade8da799..737e620061 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); #if NETCOREAPP2_1 ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp [MethodImpl(InliningOptions.ShortMethod)] internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same size!"); + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); #if NETCOREAPP2_1 ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp } [MethodImpl(InliningOptions.ShortMethod)] - private static byte ConvertToByte(float f) => (byte)ImageMaths.Clamp((f * 255f) + 0.5f, 0, 255f); + private static byte ConvertToByte(float f) => (byte)ComparableExtensions.Clamp((f * 255f) + 0.5f, 0, 255f); [Conditional("DEBUG")] private static void VerifyIsAvx2Compatible(string operation) diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs new file mode 100644 index 0000000000..3b7dea0955 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs @@ -0,0 +1,70 @@ +using System; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + public class ClampFloat + { + private readonly float min = -1.5f; + private readonly float max = 2.5f; + private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 }; + + [Benchmark(Baseline = true)] + public float UsingMathF() + { + float acc = 0; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingMathF(Values[i], this.min, this.max); + } + + return acc; + } + + [Benchmark] + public float UsingBranching() + { + float acc = 0; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingBranching(Values[i], this.min, this.max); + } + + return acc; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ClampUsingMathF(float x, float min, float max) + { + return Math.Min(max, Math.Max(min, x)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ClampUsingBranching(float x, float min, float max) + { + if (x >= max) + { + return max; + } + + if (x <= min) + { + return min; + } + + return x; + } + + // RESULTS: + // Method | Mean | Error | StdDev | Scaled | + // --------------- |---------:|----------:|----------:|-------:| + // UsingMathF | 30.37 ns | 0.3764 ns | 0.3337 ns | 1.00 | + // UsingBranching | 18.66 ns | 0.1043 ns | 0.0871 ns | 0.61 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs similarity index 98% rename from tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs index d486cb2f37..6ce82ba115 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/Clamp.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs @@ -10,7 +10,7 @@ using BenchmarkDotNet.Attributes; namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath { - public class Clamp + public class ClampInt32IntoByte { [Params(-1, 0, 255, 256)] public int Value { get; set; } diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index d8b1525bed..75ef611a5c 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers [InlineData(10.1f, -0.1f, 10, 10f)] public void Clamp(float x, float min, float max, float expected) { - float actual = ImageMaths.Clamp(x, min, max); + float actual = x.Clamp(min, max); Assert.Equal(expected, actual); } From 90c7153a6ebd8e4c8d0c24a0837d1f7aa7c340c2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 00:05:47 +0200 Subject: [PATCH 044/238] remove useless reassignment in PixelOperations{TPixel} --- src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 6c133191a1..b12a2bfa58 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -29,10 +29,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - ReadOnlySpan sourceVectors1 = sourceVectors; - GuardSpans(sourceVectors1, nameof(sourceVectors1), destinationColors, nameof(destinationColors), count); + GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors1); + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); for (int i = 0; i < count; i++) @@ -51,10 +50,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The number of pixels to convert. internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) { - ReadOnlySpan sourceColors1 = sourceColors; - GuardSpans(sourceColors1, nameof(sourceColors1), destinationVectors, nameof(destinationVectors), count); + GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors1); + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); for (int i = 0; i < count; i++) From 876f230a84435fa7b388956fe63922cad48421b9 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 00:47:23 +0200 Subject: [PATCH 045/238] fix PixelOperationsTests --- .../PixelFormats/PixelOperationsTests.cs | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 651e63bdf7..8a0aee1a7c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -15,15 +15,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { public class PixelOperationsTests { - public class Argb32OperationsTests : PixelOperationsTests - { - public const string SkipProfilingBenchmarks = + public const string SkipProfilingBenchmarks = #if true - "Profiling benchmark - enable manually!"; + "Profiling benchmark - enable manually!"; #else null; #endif + public class Argb32OperationsTests : PixelOperationsTests + { + + public Argb32OperationsTests(ITestOutputHelper output) : base(output) { } @@ -39,8 +41,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } @@ -52,8 +52,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } @@ -65,8 +63,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); @@ -163,8 +159,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); @@ -261,11 +255,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + [Fact(Skip = SkipProfilingBenchmarks)] public void Benchmark_ToVector4() { const int times = 200000; @@ -288,8 +281,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } @@ -301,8 +292,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { } - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - [Fact] public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); } From 6289a87e6d0ad5e4d1fda4385ea7fc722d1d56cb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 01:28:23 +0200 Subject: [PATCH 046/238] Better benchmarks for ToVector4() proving that the current API is fine --- .../PixelConversion/PixelConversion_ConvertToVector4.cs | 8 ++++---- ...ersion_ConvertToVector4_AsPartOfCompositeOperation.cs | 8 ++++---- .../General/PixelConversion/TestRgba.cs | 9 ++++----- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs index 29a1139912..2bc3ee9716 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs @@ -75,9 +75,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | - // ---------- |------ |---------:|----------:|----------:|-------:| - // UseRetval | 32 | 94.99 ns | 1.1199 ns | 0.9352 ns | 1.00 | - // UseCopyTo | 32 | 59.47 ns | 0.6104 ns | 0.5710 ns | 0.63 | + // Method | Count | Mean | Error | StdDev | Scaled | + // ---------- |------ |---------:|---------:|---------:|-------:| + // UseRetval | 32 | 109.0 ns | 1.202 ns | 1.125 ns | 1.00 | + // UseCopyTo | 32 | 108.6 ns | 1.151 ns | 1.020 ns | 1.00 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs index e5eb5c6cad..c6daf0f1e2 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs @@ -87,9 +87,9 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | - // ---------- |------ |----------:|----------:|----------:|-------:| - // UseRetval | 32 | 100.35 ns | 0.4844 ns | 0.4532 ns | 1.00 | - // UseCopyTo | 32 | 53.95 ns | 0.1269 ns | 0.1125 ns | 0.54 | + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------- |------ |---------:|---------:|---------:|-------:|---------:| + // UseRetval | 32 | 120.2 ns | 1.560 ns | 1.383 ns | 1.00 | 0.00 | + // UseCopyTo | 32 | 121.7 ns | 2.439 ns | 2.281 ns | 1.01 | 0.02 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index 3da7fcc4cf..cc8cf352a8 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -57,16 +57,15 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4(this.r, this.g, this.b, this.a); + return new Vector4(this.r, this.g, this.b, this.a) * new Vector4(1f / 255f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToVector4(ref Vector4 dest) { - dest.X = this.r; - dest.Y = this.g; - dest.Z = this.b; - dest.W = this.a; + var tmp = new Vector4(this.r, this.g, this.b, this.a); + tmp *= new Vector4(1f / 255f); + dest = tmp; } } } \ No newline at end of file From c0aa91d232862852f60d0dfe47ab8a3a5a1a5218 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 01:45:21 +0200 Subject: [PATCH 047/238] refactored ToRgba32() on most pixel types --- src/ImageSharp/PixelFormats/Alpha8.cs | 6 +- src/ImageSharp/PixelFormats/Argb32.cs | 8 +- src/ImageSharp/PixelFormats/Bgr24.cs | 8 +- src/ImageSharp/PixelFormats/Bgr565.cs | 5 +- src/ImageSharp/PixelFormats/Bgra32.cs | 8 +- src/ImageSharp/PixelFormats/Bgra4444.cs | 5 +- src/ImageSharp/PixelFormats/Bgra5551.cs | 5 +- src/ImageSharp/PixelFormats/Byte4.cs | 5 +- src/ImageSharp/PixelFormats/HalfSingle.cs | 5 +- src/ImageSharp/PixelFormats/HalfVector2.cs | 5 +- src/ImageSharp/PixelFormats/HalfVector4.cs | 5 +- src/ImageSharp/PixelFormats/IPixel.cs | 18 +++- .../PixelFormats/NormalizedByte2.cs | 5 +- .../PixelFormats/NormalizedByte4.cs | 5 +- .../PixelFormats/NormalizedShort2.cs | 5 +- .../PixelFormats/NormalizedShort4.cs | 5 +- .../PixelFormats/PixelBlender{TPixel}.cs | 84 +++++++++---------- src/ImageSharp/PixelFormats/Rg32.cs | 5 +- src/ImageSharp/PixelFormats/Rgba1010102.cs | 5 +- src/ImageSharp/PixelFormats/RgbaVector.cs | 5 +- src/ImageSharp/PixelFormats/Short2.cs | 5 +- src/ImageSharp/PixelFormats/Short4.cs | 5 +- 22 files changed, 148 insertions(+), 64 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs index 1e724768d0..730734f5f8 100644 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/Alpha8.cs @@ -105,7 +105,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(0, 0, 0, this.PackedValue); + public void ToRgba32(ref Rgba32 dest) + { + dest = default; + dest.A = this.PackedValue; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/Argb32.cs index 1e3bd93262..a47d7e8e78 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/Argb32.cs @@ -250,7 +250,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index ed65bebf7f..8eba08bea5 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -151,7 +151,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = byte.MaxValue; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs index 04af6ef0f1..295f1ca0a0 100644 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/Bgr565.cs @@ -113,7 +113,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 9b0ed4f96d..5d70c9e50b 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -206,7 +206,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs index db1c8f865a..29ea63e20f 100644 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/Bgra4444.cs @@ -116,7 +116,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs index 5d9003cdd3..f6dbb7811a 100644 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/Bgra5551.cs @@ -117,7 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs index 230c31c5c3..96eeeec0d4 100644 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ b/src/ImageSharp/PixelFormats/Byte4.cs @@ -117,7 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs index bef4a5dd9b..a1811e147e 100644 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/HalfSingle.cs @@ -106,7 +106,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs index 5bd9924c53..381650aec5 100644 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/HalfVector2.cs @@ -117,7 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs index 2e487ef985..b7d6687eab 100644 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/HalfVector4.cs @@ -125,7 +125,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 87125fa0a3..c0bcfa459d 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -100,8 +100,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Expands the packed representation into an . /// - /// The . - Rgba32 ToRgba32(); + /// The reference to the destination pixel + void ToRgba32(ref Rgba32 dest); /// /// Packs the pixel from an value. @@ -115,4 +115,18 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromRgba64(Rgba64 source); } + + /// + /// Temporary extension methods for compatibility + /// + internal static class PixelExtensions + { + public static Rgba32 ToRgba32(this TPixel pixel) + where TPixel : struct, IPixel + { + Rgba32 result = default; + pixel.ToRgba32(ref result); + return result; + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs index 219ec87630..9999cfe03b 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte2.cs @@ -107,7 +107,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs index d5795cb4bd..5f9124bdce 100644 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedByte4.cs @@ -128,7 +128,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs index 34e752496a..0cd8d9408f 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort2.cs @@ -123,7 +123,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs index 6fda84bc2e..21aac4d248 100644 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/NormalizedShort4.cs @@ -130,7 +130,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 63a101656e..cca4a10179 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -1,31 +1,31 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Buffers; using System.Numerics; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Abstract base class for calling pixel composition functions - /// - /// The type of the pixel - internal abstract class PixelBlender - where TPixel : struct, IPixel - { - /// - /// Blend 2 pixels together. - /// - /// The background color. - /// The source color. - /// - /// A value between 0 and 1 indicating the weight of the second source vector. - /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. - /// - /// The final pixel value after composition +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Abstract base class for calling pixel composition functions + /// + /// The type of the pixel + internal abstract class PixelBlender + where TPixel : struct, IPixel + { + /// + /// Blend 2 pixels together. + /// + /// The background color. + /// The source color. + /// + /// A value between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + /// The final pixel value after composition public abstract TPixel Blend(TPixel background, TPixel source, float amount); /// @@ -34,9 +34,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// destination span /// the background span /// the source span - /// - /// A value between 0 and 1 indicating the weight of the second source vector. - /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + /// A value between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount); @@ -46,9 +46,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// destination span /// the background span /// the source span - /// - /// A span with values between 0 and 1 indicating the weight of the second source vector. - /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + /// A span with values between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount); @@ -59,9 +59,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// the destination span /// the background span /// the source span - /// - /// A span with values between 0 and 1 indicating the weight of the second source vector. - /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + /// A span with values between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) { @@ -76,9 +76,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// the destination span /// the background span /// the source span - /// - /// A span with values between 0 and 1 indicating the weight of the second source vector. - /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + /// A span with values between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) where TPixelSrc : struct, IPixel @@ -110,9 +110,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// the destination span /// the background span /// the source span - /// - /// A value between 0 and 1 indicating the weight of the second source vector. - /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + /// A value between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) where TPixelSrc : struct, IPixel @@ -135,5 +135,5 @@ namespace SixLabors.ImageSharp.PixelFormats PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); } } - } -} + } +} diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs index 0831f6524e..878b2342f9 100644 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ b/src/ImageSharp/PixelFormats/Rg32.cs @@ -111,7 +111,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs index 14265b54e9..7f3e3a8706 100644 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/Rgba1010102.cs @@ -117,7 +117,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs index b2a3dc578e..25b8155d31 100644 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/RgbaVector.cs @@ -152,7 +152,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs index 81df3ef7b9..69a4e35e93 100644 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ b/src/ImageSharp/PixelFormats/Short2.cs @@ -129,7 +129,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs index 48bd01d6e1..653bc030f8 100644 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ b/src/ImageSharp/PixelFormats/Short4.cs @@ -134,7 +134,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4()); + public void ToRgba32(ref Rgba32 dest) + { + dest.PackFromScaledVector4(this.ToScaledVector4()); + } /// [MethodImpl(InliningOptions.ShortMethod)] From ee1ad0c01e75756a156348ed3d099422fd319e59 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 01:58:12 +0200 Subject: [PATCH 048/238] refactor ToRgba32() on the rest --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- src/ImageSharp/PixelFormats/Gray16.cs | 7 +++++-- src/ImageSharp/PixelFormats/Gray8.cs | 8 +++++++- src/ImageSharp/PixelFormats/Rgb24.cs | 8 +++++++- src/ImageSharp/PixelFormats/Rgb48.cs | 10 +++++----- src/ImageSharp/PixelFormats/Rgba32.cs | 5 ++++- src/ImageSharp/PixelFormats/Rgba64.cs | 11 +++++------ 7 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 1dc7405677..6c52eded5f 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp /// /// Scales a value from a 16 bit to it's 8 bit equivalent. /// - /// The 8 bit compoonent value. + /// The 8 bit component value. /// The [MethodImpl(InliningOptions.ShortMethod)] public static byte DownScaleFrom16BitTo8Bit(ushort component) diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/Gray16.cs index 34f221d79c..788278be4e 100644 --- a/src/ImageSharp/PixelFormats/Gray16.cs +++ b/src/ImageSharp/PixelFormats/Gray16.cs @@ -136,10 +136,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() + public void ToRgba32(ref Rgba32 dest) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(this.PackedValue); - return new Rgba32(rgb, rgb, rgb, byte.MaxValue); + dest.R = rgb; + dest.G = rgb; + dest.B = rgb; + dest.A = byte.MaxValue; } /// diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/Gray8.cs index 5812405876..8a9ec540dc 100644 --- a/src/ImageSharp/PixelFormats/Gray8.cs +++ b/src/ImageSharp/PixelFormats/Gray8.cs @@ -108,7 +108,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.PackedValue, this.PackedValue, this.PackedValue, byte.MaxValue); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + dest.A = byte.MaxValue; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index a2b896605d..0113027d62 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -165,7 +165,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue); + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = byte.MaxValue; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs index 7406fda429..815bf8c913 100644 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/Rgb48.cs @@ -165,12 +165,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() + public void ToRgba32(ref Rgba32 dest) { - byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); - byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); - byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); - return new Rgba32(r, g, b, byte.MaxValue); + dest.R = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + dest.G = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + dest.B = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + dest.A = byte.MaxValue; } /// diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 415c39c0ed..e866d1350a 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -301,7 +301,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() => this; + public void ToRgba32(ref Rgba32 dest) + { + dest = this; + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs index 738c5e3dd8..2d1a676705 100644 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/Rgba64.cs @@ -197,13 +197,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public Rgba32 ToRgba32() + public void ToRgba32(ref Rgba32 dest) { - byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); - byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); - byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); - byte a = ImageMaths.DownScaleFrom16BitTo8Bit(this.A); - return new Rgba32(r, g, b, a); + dest.R = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + dest.G = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + dest.B = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + dest.A = ImageMaths.DownScaleFrom16BitTo8Bit(this.A); } /// From 45c5e87fa4f3314cdd6583bb62105fc393907d7f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 02:15:15 +0200 Subject: [PATCH 049/238] drop all PixelExtensions usages in product code, keep in test code for now. --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 7 ++++-- src/ImageSharp/PixelFormats/IPixel.cs | 14 ------------ .../PixelFormats/PixelExtensions.cs | 22 +++++++++++++++++++ .../BinaryErrorDiffusionProcessor.cs | 5 +++-- .../BinaryOrderedDitherProcessor.cs | 5 +++-- .../Binarization/BinaryThresholdProcessor.cs | 3 ++- .../ErrorDiffusionPaletteProcessor.cs | 5 +++-- .../OrderedDitherPaletteProcessor.cs | 5 +++-- .../OctreeFrameQuantizer{TPixel}.cs | 12 ++++++---- .../Quantization/WuFrameQuantizer{TPixel}.cs | 3 ++- .../Color/Bulk/ToXyzw.cs | 3 ++- .../Transforms/AffineTransformTests.cs | 3 ++- 12 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelExtensions.cs diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 1e9dbc71a1..cf7b7b2c66 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -386,9 +386,10 @@ namespace SixLabors.ImageSharp.Formats.Png { // 8 bit grayscale + alpha // TODO: Should we consider in the future a GrayAlpha16 type. + Rgba32 rgba = default; for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { - var rgba = Unsafe.Add(ref rowSpanRef, x).ToRgba32(); + Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } @@ -645,12 +646,14 @@ namespace SixLabors.ImageSharp.Formats.Png ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan()); Span quantizedSpan = quantized.GetPixelSpan(); + Rgba32 rgba = default; + for (int i = 0; i < paletteLength; i++) { if (quantizedSpan.IndexOf((byte)i) > -1) { int offset = i * 3; - var rgba = palette[i].ToRgba32(); + palette[i].ToRgba32(ref rgba); byte alpha = rgba.A; diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index c0bcfa459d..3a6fb0a78c 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -115,18 +115,4 @@ namespace SixLabors.ImageSharp.PixelFormats /// The value. void PackFromRgba64(Rgba64 source); } - - /// - /// Temporary extension methods for compatibility - /// - internal static class PixelExtensions - { - public static Rgba32 ToRgba32(this TPixel pixel) - where TPixel : struct, IPixel - { - Rgba32 result = default; - pixel.ToRgba32(ref result); - return result; - } - } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelExtensions.cs b/src/ImageSharp/PixelFormats/PixelExtensions.cs new file mode 100644 index 0000000000..175696ab63 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelExtensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Low-performance extension methods to help conversion syntax, suitable for testing purposes. + /// + internal static class PixelExtensions + { + /// + /// Returns the result of as a new instance. + /// + public static Rgba32 ToRgba32(this TPixel pixel) + where TPixel : struct, IPixel + { + Rgba32 result = default; + pixel.ToRgba32(ref result); + return result; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs index b338ff446e..32cc2f434b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs @@ -88,7 +88,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - var rgba = sourcePixel.ToRgba32(); + Rgba32 rgba = default; + sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); @@ -105,7 +106,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - rgba = sourcePixel.ToRgba32(); + sourcePixel.ToRgba32(ref rgba); luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs index 0b28a1574b..cfdaf107c3 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs @@ -67,7 +67,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; - var rgba = sourcePixel.ToRgba32(); + Rgba32 rgba = default; + sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); @@ -84,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // rather than calculating it again. This is an inexpensive optimization. if (!previousPixel.Equals(sourcePixel)) { - rgba = sourcePixel.ToRgba32(); + sourcePixel.ToRgba32(ref rgba); luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 03b7f73e94..67dcfc7f1b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -80,6 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization configuration, rows => { + Rgba32 rgba = default; for (int y = rows.Min; y < rows.Max; y++) { Span row = source.GetPixelRowSpan(y); @@ -87,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization for (int x = startX; x < endX; x++) { ref TPixel color = ref row[x]; - var rgba = color.ToRgba32(); + color.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs index b60322799a..911d3e8fdc 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs @@ -76,7 +76,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - var rgba = sourcePixel.ToRgba32(); + Rgba32 rgba = default; + sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); @@ -101,7 +102,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - rgba = sourcePixel.ToRgba32(); + sourcePixel.ToRgba32(ref rgba); luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs index 149c7170ac..1b4910a147 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs @@ -53,7 +53,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); - var rgba = sourcePixel.ToRgba32(); + Rgba32 rgba = default; + sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); @@ -78,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering continue; } - rgba = sourcePixel.ToRgba32(); + sourcePixel.ToRgba32(ref rgba); luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 552aa8af82..29742725a0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -154,7 +154,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return this.GetClosestPixel(ref pixel); } - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); if (rgba.Equals(default)) { return this.transparentIndex; @@ -434,7 +435,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { // Go to the next level down in the tree int shift = 7 - level; - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); int index = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -529,7 +531,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (!this.leaf) { int shift = 7 - level; - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); int pixelIndex = ((rgba.B & Mask[level]) >> (shift - 2)) | ((rgba.G & Mask[level]) >> (shift - 1)) @@ -556,7 +559,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Increment(ref TPixel pixel) { - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); this.pixelCount++; this.red += rgba.R; this.green += rgba.G; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index f3b5da3202..4ef1659605 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -879,7 +879,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // Expected order r->g->b->a - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); int r = rgba.R >> (8 - IndexBits); int g = rgba.G >> (8 - IndexBits); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs index 740287e85a..0cf7087d4c 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -46,7 +46,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { TPixel c = s[i]; int i4 = i * 4; - var rgba = c.ToRgba32(); + Rgba32 rgba = default; + c.ToRgba32(ref rgba); d[i4] = rgba.R; d[i4 + 1] = rgba.G; d[i4 + 2] = rgba.B; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 17240839db..ae572498a4 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -240,7 +240,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms var white = new Rgb24(255, 255, 255); foreach (TPixel pixel in data) { - var rgba = pixel.ToRgba32(); + Rgba32 rgba = default; + pixel.ToRgba32(ref rgba); if (rgba.A == 0) { continue; From 5a070ea6d67457dfc11114adf6548a5c6a9f0770 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 02:18:28 +0200 Subject: [PATCH 050/238] wakeup message to the git status-checks --- tests/ImageSharp.Tests/Numerics/RationalTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Numerics/RationalTests.cs b/tests/ImageSharp.Tests/Numerics/RationalTests.cs index a9b9106c5c..caddd49216 100644 --- a/tests/ImageSharp.Tests/Numerics/RationalTests.cs +++ b/tests/ImageSharp.Tests/Numerics/RationalTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.Primitives; using Xunit; From 6ca596d3554974eeb37cfcb13fb8929f6050ced4 Mon Sep 17 00:00:00 2001 From: Anton Firsov Date: Mon, 22 Oct 2018 02:25:15 +0200 Subject: [PATCH 051/238] Something's wrong with the status checks --- tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs index f092da7082..950434ac32 100644 --- a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs +++ b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs @@ -2,7 +2,6 @@ using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; using Xunit; @@ -35,4 +34,4 @@ namespace SixLabors.ImageSharp.Tests.Helpers } } } -} \ No newline at end of file +} From ea5658a72a44c59fc14ee3dd09cb3d92d0b39c95 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 12:46:16 +0200 Subject: [PATCH 052/238] fix typo --- src/ImageSharp/Common/Helpers/SimdUtils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 737e620061..71eb88b1d1 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp // Deal with the remainder: if (source.Length > 0) { - ConverByteToNormalizedFloatRemainder(source, dest); + ConvertByteToNormalizedFloatRemainder(source, dest); } } @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp } [MethodImpl(InliningOptions.ColdPath)] - private static void ConverByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) + private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) { ref byte sBase = ref MemoryMarshal.GetReference(source); ref float dBase = ref MemoryMarshal.GetReference(dest); From 9bc99a6d78adfbffb1f3aab8c7e7161d58c3f5e3 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 13:00:08 +0200 Subject: [PATCH 053/238] Move all specific IPixel implementations to a (non-namespace-provider) subfolder --- src/ImageSharp/ImageSharp.csproj | 40 +++++++++---------- src/ImageSharp/ImageSharp.csproj.DotSettings | 7 +++- src/ImageSharp/PixelFormats/ComponentOrder.cs | 31 -------------- .../{ => PixelImplementations}/Alpha8.cs | 0 .../{ => PixelImplementations}/Argb32.cs | 0 .../{ => PixelImplementations}/Bgr24.cs | 0 .../{ => PixelImplementations}/Bgr565.cs | 0 .../{ => PixelImplementations}/Bgra32.cs | 0 .../{ => PixelImplementations}/Bgra4444.cs | 0 .../{ => PixelImplementations}/Bgra5551.cs | 0 .../{ => PixelImplementations}/Byte4.cs | 0 .../Argb32.PixelOperations.Generated.cs | 0 .../Argb32.PixelOperations.Generated.tt | 0 .../Bgr24.PixelOperations.Generated.cs | 0 .../Bgr24.PixelOperations.Generated.tt | 0 .../Bgra32.PixelOperations.Generated.cs | 0 .../Bgra32.PixelOperations.Generated.tt | 0 .../Gray16.PixelOperations.Generated.cs | 0 .../Gray16.PixelOperations.Generated.tt | 0 .../Gray8.PixelOperations.Generated.cs | 0 .../Gray8.PixelOperations.Generated.tt | 0 .../Rgb24.PixelOperations.Generated.cs | 0 .../Rgb24.PixelOperations.Generated.tt | 0 .../Rgb48.PixelOperations.Generated.cs | 0 .../Rgb48.PixelOperations.Generated.tt | 0 .../Rgba32.PixelOperations.Generated.cs | 0 .../Rgba32.PixelOperations.Generated.tt | 0 .../Rgba64.PixelOperations.Generated.cs | 0 .../Rgba64.PixelOperations.Generated.tt | 0 .../{ => PixelImplementations}/Gray16.cs | 0 .../{ => PixelImplementations}/Gray8.cs | 0 .../{ => PixelImplementations}/HalfSingle.cs | 0 .../{ => PixelImplementations}/HalfVector2.cs | 0 .../{ => PixelImplementations}/HalfVector4.cs | 0 .../NormalizedByte2.cs | 0 .../NormalizedByte4.cs | 0 .../NormalizedShort2.cs | 0 .../NormalizedShort4.cs | 0 .../{ => PixelImplementations}/Rg32.cs | 0 .../{ => PixelImplementations}/Rgb24.cs | 0 .../{ => PixelImplementations}/Rgb48.cs | 0 .../{ => PixelImplementations}/Rgba1010102.cs | 0 .../Rgba32.Definitions.cs | 0 .../Rgba32.PixelOperations.cs | 0 .../{ => PixelImplementations}/Rgba32.cs | 0 .../{ => PixelImplementations}/Rgba64.cs | 0 .../RgbaVector.PixelOperations.cs | 0 .../{ => PixelImplementations}/RgbaVector.cs | 0 .../{ => PixelImplementations}/Short2.cs | 0 .../{ => PixelImplementations}/Short4.cs | 0 .../PixelOperations{TPixel}.Generated.cs | 0 .../PixelOperations{TPixel}.Generated.tt | 0 52 files changed, 26 insertions(+), 52 deletions(-) delete mode 100644 src/ImageSharp/PixelFormats/ComponentOrder.cs rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Alpha8.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Argb32.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgr24.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgr565.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgra32.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgra4444.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Bgra5551.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Byte4.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Argb32.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Argb32.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Bgr24.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Bgr24.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Bgra32.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Bgra32.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Gray16.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Gray16.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Gray8.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Gray8.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgb24.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgb24.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgb48.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgb48.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgba32.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgba32.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgba64.PixelOperations.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Generated/Rgba64.PixelOperations.Generated.tt (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Gray16.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Gray8.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/HalfSingle.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/HalfVector2.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/HalfVector4.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/NormalizedByte2.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/NormalizedByte4.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/NormalizedShort2.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/NormalizedShort4.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rg32.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgb24.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgb48.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba1010102.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba32.Definitions.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba32.PixelOperations.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba32.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Rgba64.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/RgbaVector.PixelOperations.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/RgbaVector.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Short2.cs (100%) rename src/ImageSharp/PixelFormats/{ => PixelImplementations}/Short4.cs (100%) rename src/ImageSharp/PixelFormats/{Generated => }/PixelOperations{TPixel}.Generated.cs (100%) rename src/ImageSharp/PixelFormats/{Generated => }/PixelOperations{TPixel}.Generated.tt (100%) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 17e417dca8..8d2ad2abe3 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -72,43 +72,43 @@ TextTemplatingFileGenerator Block8x8F.Generated.cs - + TextTemplatingFileGenerator PixelOperations{TPixel}.Generated.cs - + TextTemplatingFileGenerator Argb32.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Bgr24.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Bgra32.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Gray8.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Gray16.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Rgb24.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Rgba32.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Rgb48.PixelOperations.Generated.cs - + TextTemplatingFileGenerator Rgba64.PixelOperations.Generated.cs @@ -137,52 +137,52 @@ True Block8x8F.Generated.tt - + True True PixelOperations{TPixel}.Generated.tt - + True True Argb32.PixelOperations.Generated.tt - + True True Bgr24.PixelOperations.Generated.tt - + True True Bgra32.PixelOperations.Generated.tt - + True True Gray8.PixelOperations.Generated.tt - + True True Gray16.PixelOperations.Generated.tt - + True True Rgb24.PixelOperations.Generated.tt - + True True Rgba32.PixelOperations.Generated.tt - + True True Rgb48.PixelOperations.Generated.tt - + True True Rgba64.PixelOperations.Generated.tt diff --git a/src/ImageSharp/ImageSharp.csproj.DotSettings b/src/ImageSharp/ImageSharp.csproj.DotSettings index 8b2e1bcf07..cd75f91b7b 100644 --- a/src/ImageSharp/ImageSharp.csproj.DotSettings +++ b/src/ImageSharp/ImageSharp.csproj.DotSettings @@ -1,3 +1,8 @@  True - True \ No newline at end of file + True + True + True + True + True + True \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/ComponentOrder.cs b/src/ImageSharp/PixelFormats/ComponentOrder.cs deleted file mode 100644 index 868d082599..0000000000 --- a/src/ImageSharp/PixelFormats/ComponentOrder.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Enumerates the various component orders. - /// - internal enum ComponentOrder - { - /// - /// Z-> Y-> X order. Equivalent to B-> G-> R in - /// - Zyx, - - /// - /// Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in - /// - Zyxw, - - /// - /// X-> Y-> Z order. Equivalent to R-> G-> B in - /// - Xyz, - - /// - /// X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in - /// - Xyzw, - } -} diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Alpha8.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Argb32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgr24.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgr565.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgra32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgra4444.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Bgra5551.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Byte4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt diff --git a/src/ImageSharp/PixelFormats/Gray16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Gray16.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs diff --git a/src/ImageSharp/PixelFormats/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Gray8.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs similarity index 100% rename from src/ImageSharp/PixelFormats/HalfSingle.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs similarity index 100% rename from src/ImageSharp/PixelFormats/HalfVector2.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/HalfVector4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs similarity index 100% rename from src/ImageSharp/PixelFormats/NormalizedByte2.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/NormalizedByte4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs similarity index 100% rename from src/ImageSharp/PixelFormats/NormalizedShort2.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/NormalizedShort4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rg32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgb24.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgb48.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba1010102.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs diff --git a/src/ImageSharp/PixelFormats/Rgba32.Definitions.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.Definitions.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba32.Definitions.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.Definitions.cs diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba64.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs diff --git a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs similarity index 100% rename from src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs similarity index 100% rename from src/ImageSharp/PixelFormats/RgbaVector.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Short2.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Short4.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs rename to src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt similarity index 100% rename from src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt rename to src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt From d4be172dcc44f19136e286cce5b855985a58ffba Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 13:39:10 +0200 Subject: [PATCH 054/238] simplify IPixel method names: PackFrom*** -> From*** --- .../Processing/GradientBrushBase{TPixel}.cs | 2 +- .../Processing/RecolorBrush{TPixel}.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 6 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 4 +- .../Formats/Png/PngScanlineProcessor.cs | 52 ++--- .../PixelFormats/ColorBuilder{TPixel}.cs | 4 +- src/ImageSharp/PixelFormats/IPixel.cs | 22 +- .../DefaultPixelBlenders.Generated.cs | 216 +++++++++--------- .../PorterDuffFunctions.Generated.cs | 216 +++++++++--------- .../PixelImplementations/Alpha8.cs | 22 +- .../PixelImplementations/Argb32.cs | 22 +- .../PixelImplementations/Bgr24.cs | 26 +-- .../PixelImplementations/Bgr565.cs | 24 +- .../PixelImplementations/Bgra32.cs | 22 +- .../PixelImplementations/Bgra4444.cs | 24 +- .../PixelImplementations/Bgra5551.cs | 24 +- .../PixelImplementations/Byte4.cs | 24 +- .../Argb32.PixelOperations.Generated.cs | 16 +- .../Bgr24.PixelOperations.Generated.cs | 16 +- .../Bgra32.PixelOperations.Generated.cs | 16 +- .../Gray16.PixelOperations.Generated.cs | 16 +- .../Gray8.PixelOperations.Generated.cs | 16 +- .../Rgb24.PixelOperations.Generated.cs | 16 +- .../Rgb48.PixelOperations.Generated.cs | 16 +- .../Rgba32.PixelOperations.Generated.cs | 16 +- .../Rgba64.PixelOperations.Generated.cs | 16 +- .../PixelImplementations/Gray16.cs | 22 +- .../PixelImplementations/Gray8.cs | 22 +- .../PixelImplementations/HalfSingle.cs | 24 +- .../PixelImplementations/HalfVector2.cs | 24 +- .../PixelImplementations/HalfVector4.cs | 26 +-- .../PixelImplementations/NormalizedByte2.cs | 24 +- .../PixelImplementations/NormalizedByte4.cs | 26 +-- .../PixelImplementations/NormalizedShort2.cs | 24 +- .../PixelImplementations/NormalizedShort4.cs | 26 +-- .../PixelFormats/PixelImplementations/Rg32.cs | 24 +- .../PixelImplementations/Rgb24.cs | 24 +- .../PixelImplementations/Rgb48.cs | 22 +- .../PixelImplementations/Rgba1010102.cs | 24 +- .../PixelImplementations/Rgba32.cs | 24 +- .../PixelImplementations/Rgba64.cs | 22 +- .../PixelImplementations/RgbaVector.cs | 24 +- .../PixelImplementations/Short2.cs | 24 +- .../PixelImplementations/Short4.cs | 26 +-- .../PixelOperations{TPixel}.Generated.cs | 36 +-- .../PixelFormats/PixelOperations{TPixel}.cs | 10 +- .../EdgeDetectorCompassProcessor.cs | 2 +- .../Processors/Dithering/ErrorDiffuserBase.cs | 2 +- .../Effects/OilPaintingProcessor.cs | 2 +- .../Processors/Filters/FilterProcessor.cs | 2 +- .../HistogramEqualizationProcessor.cs | 2 +- .../OctreeFrameQuantizer{TPixel}.cs | 2 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 2 +- .../Transforms/AffineTransformProcessor.cs | 2 +- .../ProjectiveTransformProcessor.cs | 2 +- .../Color/Bulk/PackFromVector4.cs | 2 +- .../Color/Bulk/PackFromXyzw.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 2 +- .../Drawing/FillSolidBrushTests.cs | 2 +- .../Drawing/SolidFillBlendedShapesTests.cs | 2 +- .../Formats/Jpg/GenericBlock8x8Tests.cs | 2 +- .../Jpg/Utils/LibJpegTools.ComponentData.cs | 2 +- .../Jpg/Utils/LibJpegTools.SpectralData.cs | 2 +- tests/ImageSharp.Tests/Issues/Issue594.cs | 8 +- .../PixelFormats/Alpha8Tests.cs | 2 +- .../PixelFormats/Argb32Tests.cs | 2 +- .../PixelFormats/Bgr24Tests.cs | 4 +- .../PixelFormats/Bgr565Tests.cs | 2 +- .../PixelFormats/Bgra32Tests.cs | 4 +- .../PixelFormats/Bgra4444Tests.cs | 2 +- .../PixelFormats/Bgra5551Tests.cs | 4 +- .../PixelFormats/Byte4Tests.cs | 2 +- .../PixelFormats/Gray16Tests.cs | 6 +- .../PixelFormats/Gray8Tests.cs | 6 +- .../PixelFormats/HalfSingleTests.cs | 2 +- .../PixelFormats/HalfVector2Tests.cs | 2 +- .../PixelFormats/HalfVector4Tests.cs | 2 +- .../PixelFormats/NormalizedByte2Tests.cs | 2 +- .../PixelFormats/NormalizedByte4Tests.cs | 2 +- .../PixelFormats/NormalizedShort2Tests.cs | 2 +- .../PixelFormats/NormalizedShort4Tests.cs | 2 +- .../PixelFormats/PixelOperationsTests.cs | 52 ++--- .../PixelFormats/Rg32Tests.cs | 2 +- .../PixelFormats/Rgb24Tests.cs | 4 +- .../PixelFormats/Rgb48Tests.cs | 2 +- .../PixelFormats/Rgba1010102Tests.cs | 2 +- .../PixelFormats/Rgba32Tests.cs | 24 +- .../PixelFormats/Rgba64Tests.cs | 6 +- .../PixelFormats/RgbaVectorTests.cs | 8 +- .../PixelFormats/Short2Tests.cs | 12 +- .../PixelFormats/Short4Tests.cs | 20 +- .../ImageProviders/SolidProvider.cs | 2 +- .../ImageProviders/TestPatternProvider.cs | 8 +- .../TestUtilities/ImagingTestCaseUtility.cs | 4 +- .../TestUtilities/TestImageExtensions.cs | 2 +- .../TestUtilities/TestPixel.cs | 2 +- .../Tests/TestUtilityExtensionsTests.cs | 2 +- 97 files changed, 789 insertions(+), 789 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs b/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs index 897b3f384f..00141a8d8d 100644 --- a/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing onLocalGradient); TPixel resultColor = default; - resultColor.PackFromVector4(result); + resultColor.FromVector4(result); return resultColor; } } diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs index 87e1dc146a..2968b68b55 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs @@ -95,9 +95,9 @@ namespace SixLabors.ImageSharp.Processing // Lets hack a min max extremes for a color space by letting the IPackedPixel clamp our values to something in the correct spaces :) var maxColor = default(TPixel); - maxColor.PackFromVector4(new Vector4(float.MaxValue)); + maxColor.FromVector4(new Vector4(float.MaxValue)); var minColor = default(TPixel); - minColor.PackFromVector4(new Vector4(float.MinValue)); + minColor.FromVector4(new Vector4(float.MinValue)); this.threshold = Vector4.DistanceSquared(maxColor.ToVector4(), minColor.ToVector4()) * threshold; } diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index dabab651d0..8ebfb37ebd 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int x = 0; x < width; x++) { - color.PackFromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); + color.FromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); pixelRow[x] = color; } } @@ -365,7 +365,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; - color.PackFromBgr24(Unsafe.As(ref colors[colorIndex])); + color.FromBgr24(Unsafe.As(ref colors[colorIndex])); pixelRow[newX] = color; } @@ -408,7 +408,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5), GetBytesFrom5BitValue(temp & Rgb16BMask)); - color.PackFromRgb24(rgb); + color.FromRgb24(rgb); pixelRow[x] = color; offset += 2; } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 155e6484f7..db512a0781 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -491,7 +491,7 @@ namespace SixLabors.ImageSharp.Formats.Gif int index = Unsafe.Add(ref indicesRef, i); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); Rgb24 rgb = colorTable[index]; - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); i++; } @@ -506,7 +506,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); Rgb24 rgb = colorTable[index]; - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); } i++; diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 70f2cb04b6..b4e5f201f0 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0, o = 0; x < header.Width; x++, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - pixel.PackFromGray16(new Gray16(luminance)); + pixel.FromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0; x < header.Width; x++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); - pixel.PackFromGray8(new Gray8(luminance)); + pixel.FromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.B = luminance; rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - pixel.PackFromGray16(new Gray16(luminance)); + pixel.FromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); - pixel.PackFromGray8(new Gray8(luminance)); + pixel.FromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -152,7 +152,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.B = luminance; rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -182,7 +182,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = alpha; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -201,7 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.B = luminance; rgba32.A = alpha; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = alpha; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -250,7 +250,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.B = luminance; rgba32.A = alpha; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -294,7 +294,7 @@ namespace SixLabors.ImageSharp.Formats.Png int index = Unsafe.Add(ref scanlineSpanRef, x); Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -328,7 +328,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -339,7 +339,7 @@ namespace SixLabors.ImageSharp.Formats.Png int index = Unsafe.Add(ref scanlineSpanRef, o); Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -371,7 +371,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgb48(rgb48); + pixel.FromRgb48(rgb48); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -396,7 +396,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.Rgb = rgb48; rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -411,7 +411,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.Rgb = rgb24; rgba32.A = rgb24.Equals(rgb24Trans) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -449,7 +449,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.Rgb = rgb48; rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -462,7 +462,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgb48(rgb48); + pixel.FromRgb48(rgb48); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -480,7 +480,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgba.A = rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -493,7 +493,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgb.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); - pixel.PackFromRgb24(rgb); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -520,7 +520,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -554,7 +554,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -568,7 +568,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgba.A = Unsafe.Add(ref scanlineSpanRef, o + (3 * bytesPerSample)); - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index cf66f5d5e8..2ed3164097 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats TPixel result = default; var rgba = new Rgba32(BinaryPrimitives.ReverseEndianness(packedValue)); - result.PackFromRgba32(rgba); + result.FromRgba32(rgba); return result; } @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static TPixel FromRGBA(byte red, byte green, byte blue, byte alpha) { TPixel color = default; - color.PackFromRgba32(new Rgba32(red, green, blue, alpha)); + color.FromRgba32(new Rgba32(red, green, blue, alpha)); return color; } diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 3a6fb0a78c..13e35cce05 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Sets the packed representation from a scaled . /// /// The vector to create the packed representation from. - void PackFromScaledVector4(Vector4 vector); + void FromScaledVector4(Vector4 vector); /// /// Expands the packed representation into a scaled @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Sets the packed representation from a . /// /// The vector to create the packed representation from. - void PackFromVector4(Vector4 vector); + void FromVector4(Vector4 vector); /// /// Expands the packed representation into a . @@ -59,43 +59,43 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs the pixel from an value. /// /// The value. - void PackFromArgb32(Argb32 source); + void FromArgb32(Argb32 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromBgr24(Bgr24 source); + void FromBgr24(Bgr24 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromBgra32(Bgra32 source); + void FromBgra32(Bgra32 source); /// /// Packs the Pixel from an value. /// /// The value. - void PackFromGray8(Gray8 source); + void FromGray8(Gray8 source); /// /// Packs the Pixel from an value. /// /// The value. - void PackFromGray16(Gray16 source); + void FromGray16(Gray16 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromRgb24(Rgb24 source); + void FromRgb24(Rgb24 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromRgba32(Rgba32 source); + void FromRgba32(Rgba32 source); /// /// Expands the packed representation into an . @@ -107,12 +107,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs the pixel from an value. /// /// The value. - void PackFromRgb48(Rgb48 source); + void FromRgb48(Rgb48 source); /// /// Packs the pixel from an value. /// /// The value. - void PackFromRgba64(Rgba64 source); + void FromRgba64(Rgba64 source); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 19d1c5dad1..c0a38b1a33 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -189,7 +189,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -225,7 +225,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -261,7 +261,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -333,7 +333,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -369,7 +369,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -405,7 +405,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -441,7 +441,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -477,7 +477,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -513,7 +513,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -549,7 +549,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -585,7 +585,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -621,7 +621,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -657,7 +657,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -693,7 +693,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -729,7 +729,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -765,7 +765,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -801,7 +801,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -837,7 +837,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -873,7 +873,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -909,7 +909,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -945,7 +945,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -981,7 +981,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1017,7 +1017,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1053,7 +1053,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1089,7 +1089,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1125,7 +1125,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1161,7 +1161,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1197,7 +1197,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1233,7 +1233,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1269,7 +1269,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1305,7 +1305,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1341,7 +1341,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1377,7 +1377,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1413,7 +1413,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1449,7 +1449,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1485,7 +1485,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1521,7 +1521,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1557,7 +1557,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1593,7 +1593,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1629,7 +1629,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1665,7 +1665,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1701,7 +1701,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1737,7 +1737,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1773,7 +1773,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1809,7 +1809,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1845,7 +1845,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1881,7 +1881,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1917,7 +1917,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1953,7 +1953,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1989,7 +1989,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2025,7 +2025,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2061,7 +2061,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2097,7 +2097,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2133,7 +2133,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2169,7 +2169,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2205,7 +2205,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2241,7 +2241,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2277,7 +2277,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2313,7 +2313,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2349,7 +2349,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2385,7 +2385,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2421,7 +2421,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2457,7 +2457,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2493,7 +2493,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2529,7 +2529,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2565,7 +2565,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2601,7 +2601,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2637,7 +2637,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2673,7 +2673,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2709,7 +2709,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2745,7 +2745,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2781,7 +2781,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2817,7 +2817,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2853,7 +2853,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2889,7 +2889,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2925,7 +2925,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2961,7 +2961,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2997,7 +2997,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3033,7 +3033,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3069,7 +3069,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3105,7 +3105,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3141,7 +3141,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3177,7 +3177,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3213,7 +3213,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3249,7 +3249,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3285,7 +3285,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3321,7 +3321,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3357,7 +3357,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3393,7 +3393,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3429,7 +3429,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3465,7 +3465,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3501,7 +3501,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3537,7 +3537,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3573,7 +3573,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3609,7 +3609,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3645,7 +3645,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3681,7 +3681,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3717,7 +3717,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3753,7 +3753,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3789,7 +3789,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3825,7 +3825,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3861,7 +3861,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3897,7 +3897,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index 0a6ef60eca..64148746e0 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -166,7 +166,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -238,7 +238,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -250,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -356,7 +356,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -368,7 +368,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -380,7 +380,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -392,7 +392,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -404,7 +404,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -416,7 +416,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -428,7 +428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -440,7 +440,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -452,7 +452,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -464,7 +464,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -476,7 +476,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -488,7 +488,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -594,7 +594,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -606,7 +606,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -618,7 +618,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -630,7 +630,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -642,7 +642,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -654,7 +654,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -666,7 +666,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -678,7 +678,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -690,7 +690,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -702,7 +702,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -714,7 +714,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -726,7 +726,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -832,7 +832,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -844,7 +844,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -856,7 +856,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -868,7 +868,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -880,7 +880,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -892,7 +892,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -904,7 +904,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -916,7 +916,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -928,7 +928,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -940,7 +940,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -952,7 +952,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -964,7 +964,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1070,7 +1070,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1082,7 +1082,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1094,7 +1094,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1106,7 +1106,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1118,7 +1118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1130,7 +1130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1142,7 +1142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1154,7 +1154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1166,7 +1166,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1178,7 +1178,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1190,7 +1190,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1202,7 +1202,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1308,7 +1308,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1320,7 +1320,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1332,7 +1332,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1344,7 +1344,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1356,7 +1356,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1368,7 +1368,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1380,7 +1380,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1392,7 +1392,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1404,7 +1404,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1416,7 +1416,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1428,7 +1428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1440,7 +1440,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1546,7 +1546,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1558,7 +1558,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1570,7 +1570,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1582,7 +1582,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1594,7 +1594,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1606,7 +1606,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1618,7 +1618,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1630,7 +1630,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1642,7 +1642,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1654,7 +1654,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1666,7 +1666,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1678,7 +1678,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1784,7 +1784,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1796,7 +1796,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1808,7 +1808,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1820,7 +1820,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1832,7 +1832,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1844,7 +1844,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1856,7 +1856,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1868,7 +1868,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1880,7 +1880,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1892,7 +1892,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1904,7 +1904,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1916,7 +1916,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2022,7 +2022,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2034,7 +2034,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2046,7 +2046,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2058,7 +2058,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2070,7 +2070,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2082,7 +2082,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2094,7 +2094,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2106,7 +2106,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2118,7 +2118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2130,7 +2130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2142,7 +2142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2154,7 +2154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs index 730734f5f8..75b7ede827 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -77,31 +77,31 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A; + public void FromArgb32(Argb32 source) => this.PackedValue = source.A; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; + public void FromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A; + public void FromBgra32(Bgra32 source) => this.PackedValue = source.A; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; + public void FromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; + public void FromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; + public void FromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A; + public void FromRgba32(Rgba32 source) => this.PackedValue = source.A; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -113,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; + public void FromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Compares an object with the packed vector. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index a47d7e8e78..8fc3016314 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); + public void FromVector4(Vector4 vector) => this.Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -185,11 +185,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; + public void FromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; @@ -199,7 +199,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -209,7 +209,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = source.R; this.G = source.G; @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.R = source.R; this.G = source.G; @@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -270,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 8eba08bea5..9207f046c4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -84,11 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); + rgba.FromVector4(vector); + this.FromRgba32(rgba); } /// @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -106,11 +106,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this = source; + public void FromBgr24(Bgr24 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = source.R; this.G = source.G; @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this = source.Bgr; + public void FromRgba32(Rgba32 source) => this = source.Bgr; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 295f1ca0a0..a2e4dc8802 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector3 = new Vector3(vector.X, vector.Y, vector.Z); this.PackedValue = Pack(ref vector3); @@ -85,46 +85,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToVector4()); + public void FromArgb32(Argb32 source) => this.FromVector4(source.ToVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToVector4()); + public void FromBgra32(Bgra32 source) => this.FromVector4(source.ToVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromVector4(source.ToVector4()); + public void FromRgba32(Rgba32 source) => this.FromVector4(source.ToVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 5d70c9e50b..1d156222ff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); + public void FromVector4(Vector4 vector) => this.Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; @@ -161,11 +161,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this = source; + public void FromBgra32(Bgra32 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.R = source.R; this.G = source.G; @@ -196,7 +196,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = source.R; this.G = source.G; @@ -216,7 +216,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 29ea63e20f..110b51822d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -88,46 +88,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Bgra4444 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index f6dbb7811a..dcfb25a64b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -89,46 +89,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Bgra5551 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index 96eeeec0d4..43a03dc5d1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector * 255F); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector * 255F); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -89,46 +89,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Byte4 byte4 && this.Equals(byte4); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 0b40df8dae..2fa7df94e8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index e895254576..950c6d5d90 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 2311e0bde6..f29fa78ec3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index a2d9aa755f..1b679c50a4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index de2c11d4d9..1be3cc4687 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index ad4ee2764e..c6a7c70694 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 0a1ef03873..dcc0f38024 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index bd3e014b4d..63dbc7405d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index e6f9b37a70..f92fe8ec70 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs index 788278be4e..2e98a28ada 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max * Average; this.PackedValue = (ushort)MathF.Round(vector.X + vector.Y + vector.Z); @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -108,15 +108,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + public void FromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackedValue = source.PackedValue; + public void FromGray16(Gray16 source) => this.PackedValue = source.PackedValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.PackedValue = ImageMaths.Get16BitBT709Luminance( ImageMaths.UpscaleFrom8BitTo16Bit(source.R), @@ -147,11 +147,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + public void FromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + public void FromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); /// public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs index 8a9ec540dc..d23fda7991 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector *= MaxBytes; vector += Half; @@ -80,31 +80,31 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue; + public void FromGray8(Gray8 source) => this.PackedValue = source.PackedValue; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + public void FromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + public void FromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance( ImageMaths.DownScaleFrom16BitTo8Bit(source.R), ImageMaths.DownScaleFrom16BitTo8Bit(source.G), @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance( ImageMaths.DownScaleFrom16BitTo8Bit(source.R), ImageMaths.DownScaleFrom16BitTo8Bit(source.G), diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index a1811e147e..8323cf3e8a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { float scaled = vector.X; scaled *= 2F; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); + public void FromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -78,46 +78,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 381650aec5..cb915459bc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -89,46 +89,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index b7d6687eab..9f60ca8c77 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -63,11 +63,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { vector *= 2F; vector -= Vector4.One; - this.PackFromVector4(vector); + this.FromVector4(vector); } /// @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -97,46 +97,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is HalfVector4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index 9999cfe03b..d39cfd402e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector2 = new Vector2(vector.X, vector.Y); this.PackedValue = Pack(vector2); @@ -95,46 +95,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 5f9124bdce..82698d5085 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -66,11 +66,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { vector *= 2F; vector -= Vector4.One; - this.PackFromVector4(vector); + this.FromVector4(vector); } /// @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -100,46 +100,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is NormalizedByte4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 0cd8d9408f..b9cab1e7d3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; scaled -= Vector2.One; @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector2 = new Vector2(vector.X, vector.Y); this.PackedValue = Pack(vector2); @@ -95,46 +95,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 21aac4d248..3bc74e6c67 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -66,11 +66,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { vector *= 2F; vector -= Vector4.One; - this.PackFromVector4(vector); + this.FromVector4(vector); } /// @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -102,46 +102,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is NormalizedShort4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 878b2342f9..6dc623518d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector2 = new Vector2(vector.X, vector.Y); this.PackedValue = Pack(vector2); @@ -83,46 +83,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 0113027d62..293fe0acbf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.PixelFormats var vector = new Vector4(color.ToVector3(), 1F); Rgb24 rgb = default; - rgb.PackFromScaledVector4(vector); + rgb.FromScaledVector4(vector); return rgb; } @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); + public void FromVector4(Vector4 vector) => this.Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; @@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -157,11 +157,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this = source; + public void FromRgb24(Rgb24 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this = source.Rgb; + public void FromRgba32(Rgba32 source) => this = source.Rgb; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index 815bf8c913..81497e5f18 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -124,11 +124,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this = source.Rgb; + public void FromRgba64(Rgba64 source) => this = source.Rgb; /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); this.R = rgb; @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this = source; + public void FromRgb48(Rgb48 source) => this = source; /// public override bool Equals(object obj) => obj is Rgb48 rgb48 && this.Equals(rgb48); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 7f3e3a8706..895added1b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -89,46 +89,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Rgba1010102 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index e866d1350a..5a16704ef0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -181,7 +181,7 @@ namespace SixLabors.ImageSharp.PixelFormats var vector = new Vector4(color.ToVector3(), 1F); Rgba32 rgba = default; - rgba.PackFromScaledVector4(vector); + rgba.FromScaledVector4(vector); return rgba; } @@ -224,7 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -232,7 +232,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); + public void FromVector4(Vector4 vector) => this.Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -250,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.Bgr = source; this.A = byte.MaxValue; @@ -258,7 +258,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -268,7 +268,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -278,7 +278,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); this.R = rgb; @@ -289,7 +289,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.Rgb = source; this.A = byte.MaxValue; @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this = source; + public void FromRgba32(Rgba32 source) => this = source; /// [MethodImpl(InliningOptions.ShortMethod)] @@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); @@ -318,7 +318,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) + public void FromRgba64(Rgba64 source) { this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 2d1a676705..5ae5492e23 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) + public void FromArgb32(Argb32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) + public void FromBgr24(Bgr24 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) + public void FromBgra32(Bgra32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) + public void FromGray8(Gray8 source) { ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); this.R = rgb; @@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) + public void FromGray16(Gray16 source) { this.R = source.PackedValue; this.G = source.PackedValue; @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) + public void FromRgb24(Rgb24 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -187,7 +187,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) + public void FromRgba32(Rgba32 source) { this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) + public void FromRgb48(Rgb48 source) { this.Rgb = source; this.A = ushort.MaxValue; @@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this = source; + public void FromRgba64(Rgba64 source) => this = source; /// public override bool Equals(object obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 25b8155d31..ff4c69d701 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); this.R = vector.X; @@ -124,46 +124,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Converts the value of this instance to a hexadecimal string. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 69a4e35e93..96fe15ed61 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F; scaled -= new Vector2(32767F); @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) + public void FromVector4(Vector4 vector) { var vector2 = new Vector2(vector.X, vector.Y); this.PackedValue = Pack(vector2); @@ -101,46 +101,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// /// Expands the packed representation into a . diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 653bc030f8..d224f8eb4e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -72,11 +72,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromScaledVector4(Vector4 vector) + public void FromScaledVector4(Vector4 vector) { vector *= 65534F; vector -= new Vector4(32767F); - this.PackFromVector4(vector); + this.FromVector4(vector); } /// @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); /// [MethodImpl(InliningOptions.ShortMethod)] @@ -106,46 +106,46 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { - dest.PackFromScaledVector4(this.ToScaledVector4()); + dest.FromScaledVector4(this.ToScaledVector4()); } /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(InliningOptions.ShortMethod)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); /// public override bool Equals(object obj) => obj is Short4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 66966543fc..2708af0749 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } @@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -238,7 +238,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } @@ -273,7 +273,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } @@ -343,7 +343,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -378,7 +378,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } @@ -413,7 +413,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } @@ -483,7 +483,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -518,7 +518,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } @@ -553,7 +553,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -588,7 +588,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } @@ -623,7 +623,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index f1b40e81f0..926b234d75 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static PixelOperations Instance { get; } = default(TPixel).CreatePixelOperations(); /// - /// Bulk version of + /// Bulk version of /// /// The to the source vectors. /// The to the destination colors. @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromVector4(sp); + dp.FromVector4(sp); } } @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Bulk version of + /// Bulk version of /// /// The to the source vectors. /// The to the destination colors. @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromScaledVector4(sp); + dp.FromScaledVector4(sp); } } @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.PixelFormats { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel2 dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs index ebf9c8dec2..4165cf024e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution currentPassPixel.ToVector4(), currentTargetPixel.ToVector4()); - currentTargetPixel.PackFromVector4(pixelValue); + currentTargetPixel.FromVector4(pixelValue); } } }); diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs index b407841f20..642da2f001 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering var offsetColor = pixel.ToVector4(); Vector4 result = ((error * coefficient) / this.divisorVector) + offsetColor; - pixel.PackFromVector4(result); + pixel.FromVector4(result); } } } diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index 6ad4dcba97..1b17c470ed 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4( + pixel.FromVector4( new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); } } diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs index e20b42eb7c..d3a44c066e 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters { ref TPixel pixel = ref row[x]; var vector = Vector4.Transform(pixel.ToVector4(), matrix); - pixel.PackFromVector4(vector); + pixel.FromVector4(vector); } } }); diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs index e90b352258..580adc7fe9 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization int luminance = this.GetLuminance(sourcePixel, this.LuminanceLevels); float luminanceEqualized = cdf[luminance] / numberOfPixelsMinusCdfMin; - pixels[i].PackFromVector4(new Vector4(luminanceEqualized)); + pixels[i].FromVector4(new Vector4(luminanceEqualized)); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 29742725a0..1eeb0be410 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -499,7 +499,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Set the color of the palette entry var vector = Vector3.Clamp(new Vector3(this.red, this.green, this.blue) / this.pixelCount, Vector3.Zero, new Vector3(255)); TPixel pixel = default; - pixel.PackFromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); + pixel.FromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); palette[index] = pixel; // Consume the next palette index diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 4ef1659605..dd947f337d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -199,7 +199,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization float a = Volume(ref this.colorCube[k], vmaSpan); ref TPixel color = ref this.palette[k]; - color.PackFromScaledVector4(new Vector4(r, g, b, a) / weight / 255F); + color.FromScaledVector4(new Vector4(r, g, b, a) / weight / 255F); } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 790eb80482..e12b91eab9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -218,7 +218,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Reverse the premultiplication Vector4Utils.UnPremultiply(ref sum); - dest.PackFromVector4(sum); + dest.FromVector4(sum); } } }); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index bad8eab3af..50af26aebf 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Reverse the premultiplication Vector4Utils.UnPremultiply(ref sum); - dest.PackFromVector4(sum); + dest.FromVector4(sum); } } }); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index eaa52a9750..e39c464f1a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk for (int i = 0; i < this.Count; i++) { - Unsafe.Add(ref d, i).PackFromVector4(Unsafe.Add(ref s, i)); + Unsafe.Add(ref d, i).FromVector4(Unsafe.Add(ref s, i)); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs index 7e7dfb3652..5272351045 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { int i4 = i * 4; var c = default(TPixel); - c.PackFromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); + c.FromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); d[i] = c; } } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index ff2e57b974..729971548c 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.Benchmarks float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); TPixel packed = default(TPixel); - packed.PackFromVector4( + packed.FromVector4( PremultipliedLerp( sourceColor, glowColor.ToVector4(), diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index 32f723e72a..639b3fe81a 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing vec.W = alpha; TPixel fillColor = default; - fillColor.PackFromVector4(vec); + fillColor.FromVector4(vec); using (Image image = provider.GetImage()) { diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index a8fb187ced..94e12f8581 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing var c = NamedColors.Red.ToVector4(); c.W *= 0.5f; var pixel = default(TPixel); - pixel.PackFromVector4(c); + pixel.FromVector4(c); img.Mutate( x => x.Fill( diff --git a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs index dedb094bc2..341d67f0f1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { var rgba = new Rgba32((byte)(i + 1), (byte)(j + 1), (byte)200, (byte)255); var color = default(TPixel); - color.PackFromRgba32(rgba); + color.FromRgba32(rgba); pixels[i, j] = color; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs index 57d92fa151..7acce84cea 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils var v = new Vector4(val, val, val, 1); Rgba32 color = default; - color.PackFromVector4(v); + color.FromVector4(v); int yy = by * 8 + y; int xx = bx * 8 + x; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs index bcfabca390..f5618d26d2 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils var v = new Vector4(val0, val1, val2, 1); Rgba32 color = default; - color.PackFromVector4(v); + color.FromVector4(v); int yy = by * 8 + y; int xx = bx * 8 + x; diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 4a0683fba7..48e355ea78 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests.Issues // Test PackFromScaledVector4. var pixel = default(NormalizedByte4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); Assert.Equal(0x81818181, pixel.PackedValue); // Test Ordering @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Issues float w = -0.7f; Assert.Equal(0xA740DA0D, new NormalizedByte4(x, y, z, w).PackedValue); var n = default(NormalizedByte4); - n.PackFromRgba32(new Rgba32(141, 90, 192, 39)); + n.FromRgba32(new Rgba32(141, 90, 192, 39)); Assert.Equal(0xA740DA0D, n.PackedValue); Assert.Equal((uint)958796544, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.Issues // Test PackFromScaledVector4. var pixel = default(NormalizedShort4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); // Test Ordering @@ -192,7 +192,7 @@ namespace SixLabors.ImageSharp.Tests.Issues // Test PackFromScaledVector4. var pixel = default(Short4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); // Test clamping. diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 37e7d94e4d..067c1a9779 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); // Act - alpha.PackFromScaledVector4(scaled); + alpha.FromScaledVector4(scaled); byte actual = alpha.PackedValue; // Assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 6186793c5b..31b9a53a04 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0xFFFFFFFF; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 96589a03e0..ce284f4201 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromRgba32() { var rgb = default(Bgr24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromVector4() { var rgb = default(Bgr24); - rgb.PackFromVector4(Vec(1, 2, 3, 4)); + rgb.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 8cbbf558d8..5033788b84 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var pixel = default(Bgr565); // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 1b890ac494..93993cc399 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromRgba32() { var rgb = default(Rgb24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromVector4() { var c = default(Bgra32); - c.PackFromVector4(Vec(1, 2, 3, 4)); + c.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, c.R); Assert.Equal(2, c.G); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index a2fc1a0520..3f6b7653f4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var bgra = default(Bgra4444); // act - bgra.PackFromScaledVector4(scaled); + bgra.FromScaledVector4(scaled); ushort actual = bgra.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index 084dfbd97c..eaf397bb5b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -53,10 +53,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Vector4 scaled = new Bgra5551(Vector4.One).ToScaledVector4(); int expected = 0xFFFF; var pixel = default(Bgra5551); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index de1c749f6c..c172bbdaca 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0xFFFFFFFF; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index db4fa70197..69a44a9bbf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Vector4 scaled = new Gray16(expected).ToScaledVector4(); // Act - gray.PackFromScaledVector4(scaled); + gray.FromScaledVector4(scaled); ushort actual = gray.PackedValue; // Assert @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var vector = new Gray16(expected).ToVector4(); // Act - gray.PackFromVector4(vector); + gray.FromVector4(vector); ushort actual = gray.PackedValue; // Assert @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ushort expected = ImageMaths.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); // Act - gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); + gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); ushort actual = gray.PackedValue; // Assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index aaca6c8776..7886be9e02 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Vector4 scaled = new Gray8(expected).ToScaledVector4(); // Act - gray.PackFromScaledVector4(scaled); + gray.FromScaledVector4(scaled); byte actual = gray.PackedValue; // Assert @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var vector = new Gray8(expected).ToVector4(); // Act - gray.PackFromVector4(vector); + gray.FromVector4(vector); byte actual = gray.PackedValue; // Assert @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats byte expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb); // Act - gray.PackFromRgba32(new Rgba32(rgb, rgb, rgb)); + gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); byte actual = gray.PackedValue; // Assert diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index fed55af6f7..a503db01cb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var halfSingle = default(HalfSingle); // act - halfSingle.PackFromScaledVector4(scaled); + halfSingle.FromScaledVector4(scaled); ushort actual = halfSingle.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index c775e3a0de..a892b84137 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var halfVector = default(HalfVector2); // act - halfVector.PackFromScaledVector4(scaled); + halfVector.FromScaledVector4(scaled); uint actual = halfVector.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 540a1ed08b..02a05a76f9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ulong expected = 13547034390470638592uL; // act - halfVector4.PackFromScaledVector4(scaled); + halfVector4.FromScaledVector4(scaled); ulong actual = halfVector4.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 98b747a94f..faaeae6cc1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0x8181; // act - byte2.PackFromScaledVector4(scaled); + byte2.FromScaledVector4(scaled); uint actual = byte2.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index d9cca360b2..4465fbaed3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0x81818181; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 83eab82ac8..4f66d04e35 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0x80018001; // act - short2.PackFromScaledVector4(scaled); + short2.FromScaledVector4(scaled); uint actual = short2.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 40b2d05e31..b93960dbf8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ulong expected = 0x7FFF7FFF7FFF7FFF; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 8a0aee1a7c..ef57458c96 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { - expected[i].PackFromGray8(new Gray8(source[i])); + expected[i].FromGray8(new Gray8(source[i])); } TestOperation( @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { - gray.PackFromScaledVector4(source[i].ToScaledVector4()); + gray.FromScaledVector4(source[i].ToScaledVector4()); expected[i] = gray.PackedValue; } @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i2 = i * 2; - expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); } TestOperation( @@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i2 = i * 2; - gray.PackFromScaledVector4(source[i].ToScaledVector4()); + gray.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref gray); expected[i2] = bytes[0]; expected[i2 + 1] = bytes[1]; @@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { - expected[i].PackFromGray8(new Gray8(source[i])); + expected[i].FromGray8(new Gray8(source[i])); } TestOperation( @@ -191,7 +191,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { - gray.PackFromScaledVector4(source[i].ToScaledVector4()); + gray.FromScaledVector4(source[i].ToScaledVector4()); expected[i] = gray.PackedValue; } @@ -213,7 +213,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i2 = i * 2; - expected[i].PackFromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); } TestOperation( @@ -234,7 +234,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i2 = i * 2; - gray.PackFromScaledVector4(source[i].ToScaledVector4()); + gray.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref gray); expected[i2] = bytes[0]; expected[i2 + 1] = bytes[1]; @@ -341,7 +341,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < expected.Length; i++) { - expected[i].PackFromVector4(source[i]); + expected[i].FromVector4(source[i]); } return expected; } @@ -352,7 +352,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < expected.Length; i++) { - expected[i].PackFromScaledVector4(source[i]); + expected[i].FromScaledVector4(source[i]); } return expected; } @@ -446,7 +446,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i4 = i * 4; - expected[i].PackFromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + expected[i].FromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); } TestOperation( @@ -467,7 +467,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i4 = i * 4; - argb.PackFromScaledVector4(source[i].ToScaledVector4()); + argb.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = argb.A; expected[i4 + 1] = argb.R; @@ -493,7 +493,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i3 = i * 3; - expected[i].PackFromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); + expected[i].FromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); } TestOperation( @@ -514,7 +514,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i3 = i * 3; - bgr.PackFromScaledVector4(source[i].ToScaledVector4()); + bgr.FromScaledVector4(source[i].ToScaledVector4()); expected[i3] = bgr.B; expected[i3 + 1] = bgr.G; expected[i3 + 2] = bgr.R; @@ -538,7 +538,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i4 = i * 4; - expected[i].PackFromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + expected[i].FromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); } TestOperation( @@ -559,7 +559,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i4 = i * 4; - bgra.PackFromScaledVector4(source[i].ToScaledVector4()); + bgra.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = bgra.B; expected[i4 + 1] = bgra.G; expected[i4 + 2] = bgra.R; @@ -584,7 +584,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i3 = i * 3; - expected[i].PackFromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); + expected[i].FromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); } TestOperation( @@ -605,7 +605,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i3 = i * 3; - rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + rgb.FromScaledVector4(source[i].ToScaledVector4()); expected[i3] = rgb.R; expected[i3 + 1] = rgb.G; expected[i3 + 2] = rgb.B; @@ -629,7 +629,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + expected[i].FromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); } TestOperation( @@ -650,7 +650,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i4 = i * 4; - rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + rgba.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = rgba.R; expected[i4 + 1] = rgba.G; expected[i4 + 2] = rgba.B; @@ -675,7 +675,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i6 = i * 6; - expected[i].PackFromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); + expected[i].FromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); } TestOperation( @@ -696,7 +696,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i6 = i * 6; - rgb.PackFromScaledVector4(source[i].ToScaledVector4()); + rgb.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes rgb48Bytes = Unsafe.As(ref rgb); expected[i6] = rgb48Bytes[0]; expected[i6 + 1] = rgb48Bytes[1]; @@ -724,7 +724,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + expected[i].FromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); } TestOperation( @@ -745,7 +745,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < count; i++) { int i8 = i * 8; - rgba.PackFromScaledVector4(source[i].ToScaledVector4()); + rgba.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes rgba64Bytes = Unsafe.As(ref rgba); expected[i8] = rgba64Bytes[0]; expected[i8 + 1] = rgba64Bytes[1]; @@ -799,7 +799,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < result.Length; i++) { Vector4 v = GetVector(rnd); - result[i].PackFromVector4(v); + result[i].FromVector4(v); } return result; @@ -814,7 +814,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < result.Length; i++) { Vector4 v = GetVector(rnd); - result[i].PackFromScaledVector4(v); + result[i].FromScaledVector4(v); } return result; diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 135843e35f..d4347cae65 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = rg32.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index aa6d9024cd..918a147d9e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromRgba32() { var rgb = default(Rgb24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void PackFromVector4() { var rgb = default(Rgb24); - rgb.PackFromVector4(Vec(1, 2, 3, 4)); + rgb.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 16dfd7f577..444a627926 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = short3.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); // assert Assert.Equal(expected, pixel); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 243d4a44c9..16aad79a0c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = rgba.ToScaledVector4(); - actual.PackFromScaledVector4(scaled); + actual.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 30a5f961b7..df83d14fbc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = rgba.ToScaledVector4(); - actual.PackFromScaledVector4(scaled); + actual.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(0x1a, 0, 0x80, 0); // act - actual.PackFromRgba32(rgba); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -205,8 +205,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(0x1a, 0, 0x80, 0); // act - rgba.PackFromRgba32(expected); - actual.PackFromRgba32(rgba); + rgba.FromRgba32(expected); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -221,8 +221,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Bgra32(0x1a, 0, 0x80, 0); // act - rgba.PackFromBgra32(expected); - actual.PackFromRgba32(rgba); + rgba.FromBgra32(expected); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -237,8 +237,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Argb32(0x1a, 0, 0x80, 0); // act - rgba.PackFromArgb32(expected); - actual.PackFromRgba32(rgba); + rgba.FromArgb32(expected); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -253,8 +253,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 0, 65535); // act - input.PackFromRgb48(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -269,8 +269,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 0, 65535, 0); // act - input.PackFromRgba64(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index e9ac5377d2..d6a9db66f8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = short4.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert @@ -71,8 +71,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { var zero = default(Rgba64); var one = default(Rgba64); - zero.PackFromVector4(Vector4.One * -1234.0f); - one.PackFromVector4(Vector4.One * 1234.0f); + zero.FromVector4(Vector4.One * -1234.0f); + one.FromVector4(Vector4.One * 1234.0f); Assert.Equal(Vector4.Zero, zero.ToVector4()); Assert.Equal(Vector4.One, one.ToVector4()); } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index 9b5fceac77..a6fec9e51a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -124,8 +124,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 0, 65535); // act - input.PackFromRgb48(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -140,8 +140,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 0, 65535, 0); // act - input.PackFromRgba64(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 5f2f45b3be..b15384bf6b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = short2.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 0, 255); // act - short2.PackFromRgba32(expected); + short2.FromRgba32(expected); actual = short2.ToRgba32(); // assert @@ -119,8 +119,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 65535, 0); // act - input.PackFromRgb48(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -135,8 +135,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 65535, 0, 65535); // act - input.PackFromRgba64(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 4245fcf381..6d45606bf3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act var pixel = default(Short4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 0, 255); // act - short4.PackFromRgba32(expected); + short4.FromRgba32(expected); actual = short4.ToRgba32(); // assert @@ -123,8 +123,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Bgra32(20, 38, 0, 255); // act - short4.PackFromBgra32(expected); - actual.PackFromRgba32(short4.ToRgba32()); + short4.FromBgra32(expected); + actual.FromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -139,8 +139,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Argb32(20, 38, 0, 255); // act - short4.PackFromArgb32(expected); - actual.PackFromRgba32(short4.ToRgba32()); + short4.FromArgb32(expected); + actual.FromRgba32(short4.ToRgba32()); // assert Assert.Equal(expected, actual); @@ -155,8 +155,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 0, 65535); // act - input.PackFromRgb48(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -171,8 +171,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 0, 65535, 0); // act - input.PackFromRgba64(expected); - actual.PackFromScaledVector4(input.ToScaledVector4()); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs index 97ed30b997..d68c37a768 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests { Image image = base.GetImage(); TPixel color = default(TPixel); - color.PackFromRgba32(new Rgba32(this.r, this.g, this.b, this.a)); + color.FromRgba32(new Rgba32(this.r, this.g, this.b, this.a)); image.Mutate(x => x.Fill(color)); return image; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs index 71ae60fabc..cc09dc0573 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -163,20 +163,20 @@ namespace SixLabors.ImageSharp.Tests { blue.W = red.W = green.W = (float)x / (float)right; - c.PackFromVector4(red); + c.FromVector4(red); int topBand = top; for (int y = topBand; y < top + height; y++) { pixels[x, y] = c; } topBand = topBand + height; - c.PackFromVector4(green); + c.FromVector4(green); for (int y = topBand; y < topBand + height; y++) { pixels[x, y] = c; } topBand = topBand + height; - c.PackFromVector4(blue); + c.FromVector4(blue); for (int y = topBand; y < bottom; y++) { pixels[x, y] = c; @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests t.PackedValue += stepsPerPixel; Vector4 v = t.ToVector4(); //v.W = (x - left) / (float)left; - c.PackFromVector4(v); + c.FromVector4(v); pixels[x, y] = c; } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 70b630adf1..c91ef56a1a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Tests { TPixel pixel = img[x, y]; Rgba64 rgbaPixel = default; - rgbaPixel.PackFromScaledVector4(pixel.ToScaledVector4()); + rgbaPixel.FromScaledVector4(pixel.ToScaledVector4()); ushort change = (ushort)Math.Round((perChannelChange / 255F) * 65535F); if (rgbaPixel.R + perChannelChange <= 255) @@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.Tests rgbaPixel.A -= perChannelChange; } - pixel.PackFromRgba64(rgbaPixel); + pixel.FromRgba64(rgbaPixel); img[x, y] = pixel; } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 2384333bfb..9255634b2f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -678,7 +678,7 @@ namespace SixLabors.ImageSharp.Tests { float value = bufferSpan[i] * scale; var v = new Vector4(value, value, value, 1f); - pixels[i].PackFromVector4(v); + pixels[i].FromVector4(v); } return image; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs index 7ce892edb3..e998ccd3dc 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities public TPixel AsPixel() { TPixel pix = default(TPixel); - pix.PackFromVector4(new System.Numerics.Vector4(this.Red, this.Green, this.Blue, this.Alpha)); + pix.FromVector4(new System.Numerics.Vector4(this.Red, this.Green, this.Blue, this.Alpha)); return pix; } diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs index 655f5b032c..301d0cebe6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests v /= 10; var color = default(TPixel); - color.PackFromVector4(v); + color.FromVector4(v); pixels[i, j] = color; } From 8ebe390c32e8360f49fbb368699c3c0567a1a05f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 13:54:25 +0200 Subject: [PATCH 055/238] Rename PackFrom*** -> From***: - in PixelOperations - in T4 templates - in tests --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 4 +- .../Decoder/JpegImagePostProcessor.cs | 2 +- .../Formats/Png/PngScanlineProcessor.cs | 4 +- .../PixelFormats/NamedColors{TPixel}.cs | 2 +- .../DefaultPixelBlenders.Generated.cs | 118 +--------- .../DefaultPixelBlenders.Generated.tt | 214 +++++++++--------- .../PorterDuffFunctions.Generated.tt | 2 +- .../PixelFormats/PixelBlender{TPixel}.cs | 4 +- .../Argb32.PixelOperations.Generated.cs | 2 +- .../Argb32.PixelOperations.Generated.tt | 4 +- .../Bgr24.PixelOperations.Generated.cs | 2 +- .../Bgr24.PixelOperations.Generated.tt | 4 +- .../Bgra32.PixelOperations.Generated.cs | 2 +- .../Bgra32.PixelOperations.Generated.tt | 4 +- .../Gray16.PixelOperations.Generated.cs | 2 +- .../Gray16.PixelOperations.Generated.tt | 4 +- .../Gray8.PixelOperations.Generated.cs | 2 +- .../Gray8.PixelOperations.Generated.tt | 4 +- .../Rgb24.PixelOperations.Generated.cs | 2 +- .../Rgb24.PixelOperations.Generated.tt | 4 +- .../Rgb48.PixelOperations.Generated.cs | 2 +- .../Rgb48.PixelOperations.Generated.tt | 4 +- .../Rgba32.PixelOperations.Generated.cs | 2 +- .../Rgba32.PixelOperations.Generated.tt | 4 +- .../Rgba64.PixelOperations.Generated.cs | 2 +- .../Rgba64.PixelOperations.Generated.tt | 4 +- .../Rgba32.PixelOperations.cs | 6 +- .../RgbaVector.PixelOperations.cs | 2 +- .../PixelOperations{TPixel}.Generated.cs | 82 +++---- .../PixelOperations{TPixel}.Generated.tt | 42 ++-- .../PixelFormats/PixelOperations{TPixel}.cs | 24 +- .../Convolution/Convolution2DProcessor.cs | 2 +- .../Convolution/Convolution2PassProcessor.cs | 2 +- .../Convolution/ConvolutionProcessor.cs | 2 +- .../Processors/Transforms/ResizeProcessor.cs | 2 +- .../Color/Bulk/PackFromVector4.cs | 4 +- .../Color/Bulk/PackFromXyzw.cs | 4 +- .../PixelBlenders/PorterDuffBulkVsPixel.cs | 2 +- tests/ImageSharp.Tests/Issues/Issue594.cs | 24 +- .../PixelFormats/Alpha8Tests.cs | 2 +- .../PixelFormats/Argb32Tests.cs | 2 +- .../PixelFormats/Bgr24Tests.cs | 4 +- .../PixelFormats/Bgr565Tests.cs | 2 +- .../PixelFormats/Bgra32Tests.cs | 4 +- .../PixelFormats/Bgra4444Tests.cs | 2 +- .../PixelFormats/Bgra5551Tests.cs | 2 +- .../PixelFormats/Byte4Tests.cs | 2 +- .../PixelFormats/Gray16Tests.cs | 6 +- .../PixelFormats/Gray8Tests.cs | 6 +- .../PixelFormats/HalfSingleTests.cs | 2 +- .../PixelFormats/HalfVector2Tests.cs | 2 +- .../PixelFormats/HalfVector4Tests.cs | 2 +- .../PixelFormats/NormalizedByte2Tests.cs | 2 +- .../PixelFormats/NormalizedByte4Tests.cs | 2 +- .../PixelFormats/NormalizedShort2Tests.cs | 2 +- .../PixelFormats/NormalizedShort4Tests.cs | 2 +- .../PixelFormats/PixelOperationsTests.cs | 52 ++--- .../PixelFormats/Rg32Tests.cs | 2 +- .../PixelFormats/Rgb24Tests.cs | 4 +- .../PixelFormats/Rgb48Tests.cs | 2 +- .../PixelFormats/Rgba1010102Tests.cs | 2 +- .../PixelFormats/Rgba32Tests.cs | 12 +- .../PixelFormats/Rgba64Tests.cs | 2 +- .../PixelFormats/RgbaVectorTests.cs | 4 +- .../PixelFormats/Short2Tests.cs | 8 +- .../PixelFormats/Short4Tests.cs | 12 +- .../ReferenceCodecs/MagickReferenceDecoder.cs | 4 +- .../ReferenceCodecs/SystemDrawingBridge.cs | 4 +- .../TestUtilities/TestImageExtensions.cs | 2 +- 69 files changed, 321 insertions(+), 437 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 8ebfb37ebd..77cd322221 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -436,7 +436,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.PackFromBgr24Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgr24Bytes(row.GetSpan(), pixelSpan, width); } } } @@ -461,7 +461,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.PackFromBgra32Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgra32Bytes(row.GetSpan(), pixelSpan, width); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 94382553ca..eb618dff0e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Span destRow = destination.GetPixelRowSpan(yy); - PixelOperations.Instance.PackFromVector4(this.rgbaBuffer.GetSpan(), destRow, destination.Width); + PixelOperations.Instance.FromVector4(this.rgbaBuffer.GetSpan(), destRow, destination.Width); } } } diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index b4e5f201f0..e4a2562e65 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.PackFromRgb24Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgb24Bytes(scanlineSpan, rowSpan, header.Width); } return; @@ -526,7 +526,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.PackFromRgba32Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgba32Bytes(scanlineSpan, rowSpan, header.Width); } } diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 0f42e182c5..1923faa1fc 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -739,7 +739,7 @@ namespace SixLabors.ImageSharp.PixelFormats var safe = new TPixel[constants.Length + 1]; Span constantsBytes = MemoryMarshal.Cast(constants.AsSpan()); - PixelOperations.Instance.PackFromRgba32Bytes(constantsBytes, safe, constants.Length); + PixelOperations.Instance.FromRgba32Bytes(constantsBytes, safe, constants.Length); return safe; } } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index c0a38b1a33..1d3cb53afc 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -1,11 +1,4 @@ - - - - - - - -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // @@ -33,7 +26,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders where TPixel : struct, IPixel { - internal class NormalSrc : PixelBlender { /// @@ -69,7 +61,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrc : PixelBlender { /// @@ -105,7 +96,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrc : PixelBlender { /// @@ -141,7 +131,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrc : PixelBlender { /// @@ -177,7 +166,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrc : PixelBlender { /// @@ -213,7 +201,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrc : PixelBlender { /// @@ -249,7 +236,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrc : PixelBlender { /// @@ -285,7 +271,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrc : PixelBlender { /// @@ -321,7 +306,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrc : PixelBlender { /// @@ -357,7 +341,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcAtop : PixelBlender { /// @@ -393,7 +376,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcAtop : PixelBlender { /// @@ -429,7 +411,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcAtop : PixelBlender { /// @@ -465,7 +446,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcAtop : PixelBlender { /// @@ -501,7 +481,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcAtop : PixelBlender { /// @@ -537,7 +516,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcAtop : PixelBlender { /// @@ -573,7 +551,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcAtop : PixelBlender { /// @@ -609,7 +586,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcAtop : PixelBlender { /// @@ -645,7 +621,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcAtop : PixelBlender { /// @@ -681,7 +656,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcOver : PixelBlender { /// @@ -717,7 +691,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcOver : PixelBlender { /// @@ -753,7 +726,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcOver : PixelBlender { /// @@ -789,7 +761,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcOver : PixelBlender { /// @@ -825,7 +796,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcOver : PixelBlender { /// @@ -861,7 +831,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcOver : PixelBlender { /// @@ -897,7 +866,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcOver : PixelBlender { /// @@ -933,7 +901,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcOver : PixelBlender { /// @@ -969,7 +936,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcOver : PixelBlender { /// @@ -1005,7 +971,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcIn : PixelBlender { /// @@ -1041,7 +1006,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcIn : PixelBlender { /// @@ -1077,7 +1041,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcIn : PixelBlender { /// @@ -1113,7 +1076,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcIn : PixelBlender { /// @@ -1149,7 +1111,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcIn : PixelBlender { /// @@ -1185,7 +1146,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcIn : PixelBlender { /// @@ -1221,7 +1181,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcIn : PixelBlender { /// @@ -1257,7 +1216,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcIn : PixelBlender { /// @@ -1293,7 +1251,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcIn : PixelBlender { /// @@ -1329,7 +1286,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcOut : PixelBlender { /// @@ -1365,7 +1321,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcOut : PixelBlender { /// @@ -1401,7 +1356,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcOut : PixelBlender { /// @@ -1437,7 +1391,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcOut : PixelBlender { /// @@ -1473,7 +1426,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcOut : PixelBlender { /// @@ -1509,7 +1461,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcOut : PixelBlender { /// @@ -1545,7 +1496,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcOut : PixelBlender { /// @@ -1581,7 +1531,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcOut : PixelBlender { /// @@ -1617,7 +1566,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcOut : PixelBlender { /// @@ -1653,7 +1601,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDest : PixelBlender { /// @@ -1689,7 +1636,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDest : PixelBlender { /// @@ -1725,7 +1671,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDest : PixelBlender { /// @@ -1761,7 +1706,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDest : PixelBlender { /// @@ -1797,7 +1741,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDest : PixelBlender { /// @@ -1833,7 +1776,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDest : PixelBlender { /// @@ -1869,7 +1811,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDest : PixelBlender { /// @@ -1905,7 +1846,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDest : PixelBlender { /// @@ -1941,7 +1881,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDest : PixelBlender { /// @@ -1977,7 +1916,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestAtop : PixelBlender { /// @@ -2013,7 +1951,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestAtop : PixelBlender { /// @@ -2049,7 +1986,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestAtop : PixelBlender { /// @@ -2085,7 +2021,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestAtop : PixelBlender { /// @@ -2121,7 +2056,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestAtop : PixelBlender { /// @@ -2157,7 +2091,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestAtop : PixelBlender { /// @@ -2193,7 +2126,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestAtop : PixelBlender { /// @@ -2229,7 +2161,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestAtop : PixelBlender { /// @@ -2265,7 +2196,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestAtop : PixelBlender { /// @@ -2301,7 +2231,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestOver : PixelBlender { /// @@ -2337,7 +2266,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestOver : PixelBlender { /// @@ -2373,7 +2301,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestOver : PixelBlender { /// @@ -2409,7 +2336,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestOver : PixelBlender { /// @@ -2445,7 +2371,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestOver : PixelBlender { /// @@ -2481,7 +2406,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestOver : PixelBlender { /// @@ -2517,7 +2441,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestOver : PixelBlender { /// @@ -2553,7 +2476,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestOver : PixelBlender { /// @@ -2589,7 +2511,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestOver : PixelBlender { /// @@ -2625,7 +2546,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestIn : PixelBlender { /// @@ -2661,7 +2581,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestIn : PixelBlender { /// @@ -2697,7 +2616,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestIn : PixelBlender { /// @@ -2733,7 +2651,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestIn : PixelBlender { /// @@ -2769,7 +2686,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestIn : PixelBlender { /// @@ -2805,7 +2721,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestIn : PixelBlender { /// @@ -2841,7 +2756,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestIn : PixelBlender { /// @@ -2877,7 +2791,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestIn : PixelBlender { /// @@ -2913,7 +2826,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestIn : PixelBlender { /// @@ -2949,7 +2861,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestOut : PixelBlender { /// @@ -2985,7 +2896,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestOut : PixelBlender { /// @@ -3021,7 +2931,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestOut : PixelBlender { /// @@ -3057,7 +2966,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestOut : PixelBlender { /// @@ -3093,7 +3001,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestOut : PixelBlender { /// @@ -3129,7 +3036,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestOut : PixelBlender { /// @@ -3165,7 +3071,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestOut : PixelBlender { /// @@ -3201,7 +3106,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestOut : PixelBlender { /// @@ -3237,7 +3141,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestOut : PixelBlender { /// @@ -3273,7 +3176,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalClear : PixelBlender { /// @@ -3309,7 +3211,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyClear : PixelBlender { /// @@ -3345,7 +3246,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddClear : PixelBlender { /// @@ -3381,7 +3281,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractClear : PixelBlender { /// @@ -3417,7 +3316,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenClear : PixelBlender { /// @@ -3453,7 +3351,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenClear : PixelBlender { /// @@ -3489,7 +3386,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenClear : PixelBlender { /// @@ -3525,7 +3421,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayClear : PixelBlender { /// @@ -3561,7 +3456,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightClear : PixelBlender { /// @@ -3597,7 +3491,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalXor : PixelBlender { /// @@ -3633,7 +3526,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyXor : PixelBlender { /// @@ -3669,7 +3561,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddXor : PixelBlender { /// @@ -3705,7 +3596,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractXor : PixelBlender { /// @@ -3741,7 +3631,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenXor : PixelBlender { /// @@ -3777,7 +3666,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenXor : PixelBlender { /// @@ -3813,7 +3701,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenXor : PixelBlender { /// @@ -3849,7 +3736,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayXor : PixelBlender { /// @@ -3885,7 +3771,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightXor : PixelBlender { /// @@ -3921,6 +3806,5 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index f776da7a02..b7ea7a9d43 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -1,114 +1,114 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> -<#@ output extension=".cs" #> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ output extension=".cs" #> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// using System; using System.Numerics; using System.Buffers; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; - -namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders -{ - /// - /// Collection of Porter Duff alpha blending functions applying different composition models. - /// - /// - /// These functions are designed to be a general solution for all color cases, - /// that is, they take in account the alpha value of both the backdrop - /// and source, and there's no need to alpha-premultiply neither the backdrop - /// nor the source. - /// Note there are faster functions for when the backdrop color is known - /// to be opaque - /// - internal static class DefaultPixelBlenders - where TPixel : struct, IPixel - { - -<# - string[] composers = new []{ - "Src", - "SrcAtop", - "SrcOver", - "SrcIn", - "SrcOut", - "Dest", - "DestAtop", - "DestOver", - "DestIn", - "DestOut", - "Clear", - "Xor", - }; - - string[] blenders = new []{ - "Normal", - "Multiply", - "Add", - "Subtract", - "Screen", - "Darken", - "Lighten", - "Overlay", - "HardLight" - }; - - foreach(var composer in composers) { - foreach(var blender in blenders) { - - string blender_composer= $"{blender}{composer}"; - -#> - internal class <#= blender_composer#> : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static <#=blender_composer#> Instance { get; } = new <#=blender_composer#>(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders +{ + /// + /// Collection of Porter Duff alpha blending functions applying different composition models. + /// + /// + /// These functions are designed to be a general solution for all color cases, + /// that is, they take in account the alpha value of both the backdrop + /// and source, and there's no need to alpha-premultiply neither the backdrop + /// nor the source. + /// Note there are faster functions for when the backdrop color is known + /// to be opaque + /// + internal static class DefaultPixelBlenders + where TPixel : struct, IPixel + { + +<# + string[] composers = new []{ + "Src", + "SrcAtop", + "SrcOver", + "SrcIn", + "SrcOut", + "Dest", + "DestAtop", + "DestOver", + "DestIn", + "DestOut", + "Clear", + "Xor", + }; + + string[] blenders = new []{ + "Normal", + "Multiply", + "Add", + "Subtract", + "Screen", + "Darken", + "Lighten", + "Overlay", + "HardLight" + }; + + foreach(var composer in composers) { + foreach(var blender in blenders) { + + string blender_composer= $"{blender}{composer}"; + +#> + internal class <#= blender_composer#> : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static <#=blender_composer#> Instance { get; } = new <#=blender_composer#>(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - amount = amount.Clamp(0, 1); - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount[i].Clamp(0, 1)); - } - } - } - -<# - } - } - -#> - } + dest.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + +<# + } + } + +#> + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 73c835e606..e21a78031f 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index cca4a10179..48a83335a0 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.PixelFormats this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4(destinationSpan, destination, destination.Length); } } @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.PixelFormats this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4(destinationSpan, destination, destination.Length); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 2fa7df94e8..16121d62d8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index f35adee022..f903846719 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromArgb32(sp); + dp.FromArgb32(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 950c6d5d90..cbfbe70991 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt index 76163549b0..0f7bd838ff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgr24(sp); + dp.FromBgr24(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index f29fa78ec3..edd702e0e0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt index 4c2925d18f..4c4e10fad0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromBgra32(sp); + dp.FromBgra32(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index 1b679c50a4..ca0e1fe326 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt index b900e343a7..1e500dac54 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray16(sp); + dp.FromGray16(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 1be3cc4687..6950c337d6 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt index 4590420e57..7c6e2f7675 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromGray8(sp); + dp.FromGray8(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index c6a7c70694..53234cd66e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt index 6a10b401f4..b98e1e4c7c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb24(sp); + dp.FromRgb24(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index dcc0f38024..61d13978ab 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt index e38c85bf62..2ff3125b4c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgb48(sp); + dp.FromRgb48(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index 63dbc7405d..ae2ffd6888 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations { /// - internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt index 23d0be740e..fb8d6db349 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba32(sp); + dp.FromRgba32(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations { /// - internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index f92fe8ec70..252068828e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt index e998341570..626f2316d3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt @@ -26,7 +26,7 @@ ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromRgba64(sp); + dp.FromRgba64(sp); } } <# @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index 13432e58f8..4da9f101bc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); @@ -52,9 +52,9 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { - this.PackFromVector4(sourceVectors, destinationColors, count); + this.FromVector4(sourceVectors, destinationColors, count); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index aae6ee6940..ae64ed4de3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 2708af0749..f1d426389b 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -1,13 +1,13 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. - // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - public partial class PixelOperations { /// @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -33,16 +33,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -103,16 +103,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -173,16 +173,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromGray8(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -243,16 +243,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -296,7 +296,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromGray16(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -313,16 +313,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -366,7 +366,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -383,16 +383,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -436,7 +436,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -453,16 +453,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -506,7 +506,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -523,16 +523,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// @@ -576,7 +576,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -593,16 +593,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); } /// diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index 913dabb087..723b0358fe 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -11,7 +11,7 @@ <#@ output extension=".cs" #> <# - void GeneratePackFromMethods(string pixelType) + void GenerateFromMethods(string pixelType) { #> @@ -21,7 +21,7 @@ /// The source of data. /// The to the destination pixels. /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) + internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -33,21 +33,21 @@ ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFrom<#=pixelType#>(sp); + dp.From<#=pixelType#>(sp); } } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void From<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); + this.From<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); } <# @@ -74,7 +74,7 @@ ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); - dp.PackFromScaledVector4(sp.ToScaledVector4()); + dp.FromScaledVector4(sp.ToScaledVector4()); } } @@ -96,42 +96,42 @@ #> // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. - // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - public partial class PixelOperations {<# - GeneratePackFromMethods("Argb32"); + GenerateFromMethods("Argb32"); GenerateToDestFormatMethods("Argb32"); - GeneratePackFromMethods("Bgr24"); + GenerateFromMethods("Bgr24"); GenerateToDestFormatMethods("Bgr24"); - GeneratePackFromMethods("Bgra32"); + GenerateFromMethods("Bgra32"); GenerateToDestFormatMethods("Bgra32"); - GeneratePackFromMethods("Gray8"); + GenerateFromMethods("Gray8"); GenerateToDestFormatMethods("Gray8"); - GeneratePackFromMethods("Gray16"); + GenerateFromMethods("Gray16"); GenerateToDestFormatMethods("Gray16"); - GeneratePackFromMethods("Rgb24"); + GenerateFromMethods("Rgb24"); GenerateToDestFormatMethods("Rgb24"); - GeneratePackFromMethods("Rgba32"); + GenerateFromMethods("Rgba32"); GenerateToDestFormatMethods("Rgba32"); - GeneratePackFromMethods("Rgb48"); + GenerateFromMethods("Rgb48"); GenerateToDestFormatMethods("Rgb48"); - GeneratePackFromMethods("Rgba64"); + GenerateFromMethods("Rgba64"); GenerateToDestFormatMethods("Rgba64"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 926b234d75..af7690c62d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The to the source vectors. /// The to the destination colors. /// The number of pixels to convert. - internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal virtual void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The to the source vectors. /// The to the destination colors. /// The number of pixels to convert. - internal virtual void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal virtual void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) { GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); @@ -108,12 +108,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Performs a bulk conversion of a collection of one pixel format into another. /// - /// The pixel format. + /// The pixel format. /// The to the source colors. /// The to the destination colors. /// The number of pixels to convert. - internal virtual void To(ReadOnlySpan sourceColors, Span destinationColors, int count) - where TPixel2 : struct, IPixel + internal virtual void To(ReadOnlySpan sourceColors, Span destinationColors, int count) + where TDestinationPixel : struct, IPixel { GuardSpans(sourceColors, nameof(sourceColors), destinationColors, nameof(destinationColors), count); @@ -121,11 +121,11 @@ namespace SixLabors.ImageSharp.PixelFormats // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm. - // One of the requirements of PackFromScaledVector4/ToScaledVector4 is that it unaware of this and + // One of the requirements of FromScaledVector4/ToScaledVector4 is that it unaware of this and // packs/unpacks the pixel without and conversion so we employ custom methods do do this. - if (typeof(TPixel2).Equals(typeof(Gray16))) + if (typeof(TDestinationPixel) == typeof(Gray16)) { - ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); @@ -136,9 +136,9 @@ namespace SixLabors.ImageSharp.PixelFormats return; } - if (typeof(TPixel2).Equals(typeof(Gray8))) + if (typeof(TDestinationPixel) == typeof(Gray8)) { - ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); @@ -150,11 +150,11 @@ namespace SixLabors.ImageSharp.PixelFormats } // Normal converson - ref TPixel2 destRef = ref MemoryMarshal.GetReference(destinationColors); + ref TDestinationPixel destRef = ref MemoryMarshal.GetReference(destinationColors); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel2 dp = ref Unsafe.Add(ref destRef, i); + ref TDestinationPixel dp = ref Unsafe.Add(ref destRef, i); dp.FromScaledVector4(sp.ToScaledVector4()); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 0669a12470..df4df64cad 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 1f47649e6f..03447531ef 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index d2f3f8fc58..a42b777feb 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); } }); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 812c0578b2..5bd61aab19 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.PackFromVector4(tempRowSpan, targetRowSpan, tempRowSpan.Length); + PixelOperations.Instance.FromVector4(tempRowSpan, targetRowSpan, tempRowSpan.Length); } }); } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs index e39c464f1a..3839bf58ee 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs @@ -59,13 +59,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().FromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs index 5272351045..b1025e80ce 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs @@ -55,13 +55,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void CommonBulk() { - new PixelOperations().PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] public void OptimizedBulk() { - PixelOperations.Instance.PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index d9cf65d4be..46b58f369d 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Benchmarks destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromVector4(destinationSpan, destination, destination.Length); } } diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 48e355ea78..927f0a5edc 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(0, scaled.Z); Assert.Equal(0, scaled.W); - // Test PackFromScaledVector4. + // Test FromScaledVector4. var pixel = default(NormalizedByte4); pixel.FromScaledVector4(scaled); Assert.Equal(0x81818181, pixel.PackedValue); @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Tests.Issues // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 //var r = default(NormalizedByte4); - //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.FromRgba32(new Rgba32(9, 115, 202, 127)); //r.ToRgba32(ref rgba); //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); @@ -80,12 +80,12 @@ namespace SixLabors.ImageSharp.Tests.Issues //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); //r = default(NormalizedByte4); - //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.FromArgb32(new Argb32(9, 115, 202, 127)); //r.ToArgb32(ref argb); //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); //r = default(NormalizedByte4); - //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.FromBgra32(new Bgra32(9, 115, 202, 127)); //r.ToBgra32(ref bgra); //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); } @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(1, scaled.Z); Assert.Equal(1, scaled.W); - // Test PackFromScaledVector4. + // Test FromScaledVector4. var pixel = default(NormalizedShort4); pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); @@ -149,17 +149,17 @@ namespace SixLabors.ImageSharp.Tests.Issues //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); //var r = default(NormalizedShort4); - //r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); + //r.FromRgba32(new Rgba32(9, 115, 202, 127)); //r.ToRgba32(ref rgba); //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); //r = default(NormalizedShort4); - //r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); + //r.FromBgra32(new Bgra32(9, 115, 202, 127)); //r.ToBgra32(ref bgra); //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); //r = default(NormalizedShort4); - //r.PackFromArgb32(new Argb32(9, 115, 202, 127)); + //r.FromArgb32(new Argb32(9, 115, 202, 127)); //r.ToArgb32(ref argb); //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); } @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(1, scaled.Z); Assert.Equal(1, scaled.W); - // Test PackFromScaledVector4. + // Test FromScaledVector4. var pixel = default(Short4); pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); @@ -234,17 +234,17 @@ namespace SixLabors.ImageSharp.Tests.Issues //Assert.Equal(argb, new Argb32(172, 177, 243, 128)); //var r = default(Short4); - //r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); + //r.FromRgba32(new Rgba32(20, 38, 0, 255)); //r.ToRgba32(ref rgba); //Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); //r = default(Short4); - //r.PackFromBgra32(new Bgra32(20, 38, 0, 255)); + //r.FromBgra32(new Bgra32(20, 38, 0, 255)); //r.ToBgra32(ref bgra); //Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); //r = default(Short4); - //r.PackFromArgb32(new Argb32(20, 38, 0, 255)); + //r.FromArgb32(new Argb32(20, 38, 0, 255)); //r.ToArgb32(ref argb); //Assert.Equal(argb, new Argb32(20, 38, 0, 255)); } diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 067c1a9779..148b928fac 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Alpha8_PackFromScaledVector4() + public void Alpha8_FromScaledVector4() { // Arrange Alpha8 alpha = default; diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 31b9a53a04..b9f7414900 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Argb32_PackFromScaledVector4() + public void Argb32_FromScaledVector4() { // arrange Vector4 scaled = new Argb32(Vector4.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index ce284f4201..2295fbe56f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] - public void PackFromRgba32() + public void FromRgba32() { var rgb = default(Bgr24); rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats a / 255f); [Fact] - public void PackFromVector4() + public void FromVector4() { var rgb = default(Bgr24); rgb.FromVector4(Vec(1, 2, 3, 4)); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 5033788b84..967e358e1e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Bgr565_PackFromScaledVector4() + public void Bgr565_FromScaledVector4() { // arrange Vector4 scaled = new Bgr565(Vector3.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 93993cc399..a5c53ed8b0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] - public void PackFromRgba32() + public void FromRgba32() { var rgb = default(Rgb24); rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats a / 255f); [Fact] - public void PackFromVector4() + public void FromVector4() { var c = default(Bgra32); c.FromVector4(Vec(1, 2, 3, 4)); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 3f6b7653f4..8b56ec19fe 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Bgra4444_PackFromScaledVector4() + public void Bgra4444_FromScaledVector4() { // arrange Vector4 scaled = new Bgra4444(Vector4.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index eaf397bb5b..76edee8a73 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Bgra5551_PackFromScaledVector4() + public void Bgra5551_FromScaledVector4() { // arrange Vector4 scaled = new Bgra5551(Vector4.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index c172bbdaca..8391ef25ae 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Byte4_PackFromScaledVector4() + public void Byte4_FromScaledVector4() { // arrange Vector4 scaled = new Byte4(Vector4.One * 255).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index 69a44a9bbf..220ca2899a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats => Assert.Equal(input, new Gray16(input).PackedValue); [Fact] - public void Gray16_PackFromScaledVector4() + public void Gray16_FromScaledVector4() { // Arrange Gray16 gray = default; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray16_PackFromVector4() + public void Gray16_FromVector4() { // Arrange Gray16 gray = default; @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray16_PackFromRgba32() + public void Gray16_FromRgba32() { // Arrange Gray16 gray = default; diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index 7886be9e02..988002c099 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats => Assert.Equal(input, new Gray8(input).PackedValue); [Fact] - public void Gray8_PackFromScaledVector4() + public void Gray8_FromScaledVector4() { // Arrange Gray8 gray = default; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray8_PackFromVector4() + public void Gray8_FromVector4() { // Arrange Gray8 gray = default; @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Gray8_PackFromRgba32() + public void Gray8_FromRgba32() { // Arrange Gray8 gray = default; diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index a503db01cb..85a3b8b320 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void HalfSingle_PackFromScaledVector4() + public void HalfSingle_FromScaledVector4() { // arrange Vector4 scaled = new HalfSingle(-1F).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index a892b84137..ccdd23e8fb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void HalfVector2_PackFromScaledVector4() + public void HalfVector2_FromScaledVector4() { // arrange Vector4 scaled = new HalfVector2(Vector2.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 02a05a76f9..c61dd97d2a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void HalfVector4_PackFromScaledVector4() + public void HalfVector4_FromScaledVector4() { // arrange var halfVector4 = default(HalfVector4); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index faaeae6cc1..506ebe0fe0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedByte2_PackFromScaledVector4() + public void NormalizedByte2_FromScaledVector4() { // arrange Vector4 scaled = new NormalizedByte2(-Vector2.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 4465fbaed3..19a49e5d8a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedByte4_PackFromScaledVector4() + public void NormalizedByte4_FromScaledVector4() { // arrange var pixel = default(NormalizedByte4); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 4f66d04e35..216ed4ad75 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedShort2_PackFromScaledVector4() + public void NormalizedShort2_FromScaledVector4() { // arrange Vector4 scaled = new NormalizedShort2(-Vector2.One).ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index b93960dbf8..d06d46d06f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedShort4_PackFromScaledVector4() + public void NormalizedShort4_FromScaledVector4() { // arrange var pixel = default(NormalizedShort4); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index ef57458c96..958c4744ad 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromGray8Bytes(int count) + public void FromGray8Bytes(int count) { byte[] source = CreateByteTestData(count); var expected = new Gray8[count]; @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) ); } @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromGray16Bytes(int count) + public void FromGray16Bytes(int count) { byte[] source = CreateByteTestData(count * 2); Span sourceSpan = source.AsSpan(); @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) ); } @@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromGray8Bytes(int count) + public void FromGray8Bytes(int count) { byte[] source = CreateByteTestData(count); var expected = new Gray16[count]; @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) ); } @@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromGray16Bytes(int count) + public void FromGray16Bytes(int count) { byte[] source = CreateByteTestData(count * 2); Span sourceSpan = source.AsSpan(); @@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) ); } @@ -359,7 +359,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromVector4(int count) + public void FromVector4(int count) { Vector4[] source = CreateVector4TestData(count); TPixel[] expected = CreateExpectedPixelData(source); @@ -367,13 +367,13 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromVector4(s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromScaledVector4(int count) + public void FromScaledVector4(int count) { Vector4[] source = CreateVector4TestData(count); TPixel[] expected = CreateScaledExpectedPixelData(source); @@ -381,7 +381,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromScaledVector4(s, d.GetSpan(), count) ); } @@ -437,7 +437,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) + public void FromArgb32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; @@ -452,7 +452,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromArgb32Bytes(s, d.GetSpan(), count) ); } @@ -484,7 +484,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) + public void FromBgr24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; @@ -499,7 +499,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgr24Bytes(s, d.GetSpan(), count) ); } @@ -529,7 +529,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) + public void FromBgra32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; @@ -544,7 +544,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgra32Bytes(s, d.GetSpan(), count) ); } @@ -575,7 +575,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) + public void FromRgb24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; @@ -590,7 +590,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb24Bytes(s, d.GetSpan(), count) ); } @@ -620,7 +620,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) + public void FromRgba32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; @@ -635,7 +635,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba32Bytes(s, d.GetSpan(), count) ); } @@ -666,7 +666,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) + public void FromRgb48Bytes(int count) { byte[] source = CreateByteTestData(count * 6); Span sourceSpan = source.AsSpan(); @@ -681,7 +681,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb48Bytes(s, d.GetSpan(), count) ); } @@ -715,7 +715,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) + public void FromRgba64Bytes(int count) { byte[] source = CreateByteTestData(count * 8); Span sourceSpan = source.AsSpan(); @@ -730,7 +730,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba64Bytes(s, d.GetSpan(), count) ); } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index d4347cae65..46e5fbc3cd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rg32_PackFromScaledVector4() + public void Rg32_FromScaledVector4() { // arrange var rg32 = new Rg32(Vector2.One); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index 918a147d9e..a60509146d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void PackFromRgba32() + public void FromRgba32() { var rgb = default(Rgb24); rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats a / 255f); [Fact] - public void PackFromVector4() + public void FromVector4() { var rgb = default(Rgb24); rgb.FromVector4(Vec(1, 2, 3, 4)); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 444a627926..a7f0e5edfc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); [Fact] - public void Rgb48_PackFromScaledVector4() + public void Rgb48_FromScaledVector4() { // arrange var pixel = default(Rgb48); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 16aad79a0c..ad7df30769 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba1010102_PackFromScaledVector4() + public void Rgba1010102_FromScaledVector4() { // arrange var rgba = new Rgba1010102(Vector4.One); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index df83d14fbc..8c702f66da 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromScaledVector4() + public void Rgba32_FromScaledVector4() { // arrange var rgba = new Rgba32(Vector4.One); @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromRgba32_ToRgba32() + public void Rgba32_FromRgba32_ToRgba32() { // arrange var rgba = default(Rgba32); @@ -213,7 +213,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromBgra32_ToRgba32() + public void Rgba32_FromBgra32_ToRgba32() { // arrange var rgba = default(Rgba32); @@ -229,7 +229,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromArgb32_ToArgb32() + public void Rgba32_FromArgb32_ToArgb32() { // arrange var rgba = default(Rgba32); @@ -245,7 +245,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromRgb48() + public void Rgba32_FromRgb48() { // arrange var input = default(Rgba32); @@ -261,7 +261,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromRgba64() + public void Rgba32_FromRgba64() { // arrange var input = default(Rgba32); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index d6a9db66f8..564c26b8b1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba64_PackFromScaledVector4() + public void Rgba64_FromScaledVector4() { // arrange var pixel = default(Rgba64); diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index a6fec9e51a..e880e38517 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void RgbaVector_PackFromRgb48() + public void RgbaVector_FromRgb48() { // arrange var input = default(RgbaVector); @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void RgbaVector_PackFromRgba64() + public void RgbaVector_FromRgba64() { // arrange var input = default(RgbaVector); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index b15384bf6b..725e1a0d14 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromScaledVector4() + public void Short2_FromScaledVector4() { // arrange var pixel = default(Short2); @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromRgba32_ToRgba32() + public void Short2_FromRgba32_ToRgba32() { // arrange var short2 = default(Short2); @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromRgb48() + public void Short2_FromRgb48() { // arrange var input = default(Short2); @@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromRgba64() + public void Short2_FromRgba64() { // arrange var input = default(Short2); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 6d45606bf3..b19917f34a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromScaledVector4() + public void Short4_FromScaledVector4() { // arrange var short4 = new Short4(Vector4.One * 0x7FFF); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromRgba32_ToRgba32() + public void Short4_FromRgba32_ToRgba32() { // arrange var short4 = default(Short4); @@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromBgra32_ToRgba32() + public void Short4_FromBgra32_ToRgba32() { // arrange var short4 = default(Short4); @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromArgb32_ToRgba32() + public void Short4_FromArgb32_ToRgba32() { // arrange var short4 = default(Short4); @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromRgb48_ToRgb48() + public void Short4_FromRgb48_ToRgb48() { // arrange var input = default(Short4); @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromRgba64_ToRgba64() + public void Short4_FromRgba64_ToRgba64() { // arrange var input = default(Short4); diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 7e942691e9..2409ff9add 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -31,14 +31,14 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); - PixelOperations.Instance.PackFromRgba32Bytes(data, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba32Bytes(data, resultPixels, resultPixels.Length); } else if (magickImage.Depth == 16) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); - PixelOperations.Instance.PackFromRgba64Bytes(bytes, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba64Bytes(bytes, resultPixels, resultPixels.Length); } else { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index d06f5630f4..1543e2c8f4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.PackFromBgra32(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgra32(workBuffer.GetSpan(), row, row.Length); } } } @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.PackFromBgr24(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgr24(workBuffer.GetSpan(), row, row.Length); } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 9255634b2f..78927dece3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests v.W = 1F; } - PixelOperations.Instance.PackFromScaledVector4(tempSpan, pixelSpan, pixelSpan.Length); + PixelOperations.Instance.FromScaledVector4(tempSpan, pixelSpan, pixelSpan.Length); } } }); From 5fda8d38be006a90de4810b1220eff453050d424 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 13:56:47 +0200 Subject: [PATCH 056/238] rename stuff in Benchmarks --- .../Color/Bulk/{PackFromXyzw.cs => FromRgba32Bytes.cs} | 4 ++-- .../Color/Bulk/{PackFromVector4.cs => FromVector4.cs} | 4 ++-- .../PixelConversion/PixelConversion_ConvertFromRgba32.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename tests/ImageSharp.Benchmarks/Color/Bulk/{PackFromXyzw.cs => FromRgba32Bytes.cs} (94%) rename tests/ImageSharp.Benchmarks/Color/Bulk/{PackFromVector4.cs => FromVector4.cs} (98%) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs index b1025e80ce..f3245ebaf5 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs @@ -13,7 +13,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - public abstract class PackFromXyzw + public abstract class FromRgba32Bytes where TPixel : struct, IPixel { private IMemoryOwner destination; @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - public class PackFromXyzw_Rgba32 : PackFromXyzw + public class FromRgba32BytesRgba32 : FromRgba32Bytes { } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs similarity index 98% rename from tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 3839bf58ee..72322f0d44 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -17,7 +17,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { [Config(typeof(Config.ShortClr))] - public abstract class PackFromVector4 + public abstract class FromVector4 where TPixel : struct, IPixel { protected IMemoryOwner source; @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - public class PackFromVector4_Rgba32 : PackFromVector4 + public class FromVector4Rgba32 : FromVector4 { [Benchmark] public void FallbackIntrinsics128() diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 046c7dd90c..6a96c8576e 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -133,6 +133,6 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion * !!! Conclusion !!! * All memory-incompatible (permuted) variants are equivalent with the the "FromBytes" solution. * In memory compatible cases we should use the optimized Bulk-copying variant anyways, - * so there is no benefit introducing non-bulk API-s other than PackFromBytes() OR PackFromRgba32(). + * so there is no benefit introducing non-bulk API-s other than FromBytes() OR FromRgba32(). */ } \ No newline at end of file From fb1eba4f3de60b45bf4b816e4d7229c230593449 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 14:18:15 +0200 Subject: [PATCH 057/238] Introduce RgbaCompatible.Common.ttinclude --- .../Argb32.PixelOperations.Generated.cs | 12 ++-- .../Argb32.PixelOperations.Generated.tt | 58 +++---------------- .../Generated/RgbaCompatible.Common.ttinclude | 36 ++++++++++++ 3 files changed, 51 insertions(+), 55 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 16121d62d8..507c8cd3ac 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -1,19 +1,19 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. - // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Argb32 { - /// /// Provides optimized overrides for bulk operations. /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index f903846719..4324211666 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -1,53 +1,13 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="RgbaCompatible.Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Argb32 { - /// /// Provides optimized overrides for bulk operations. /// @@ -70,14 +30,14 @@ namespace SixLabors.ImageSharp.PixelFormats } <# - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateDefaultConvertToMethod("Argb32", "Bgr24"); + GenerateDefaultConvertToMethod("Argb32", "Bgra32"); + GenerateDefaultConvertToMethod("Argb32", "Gray8"); + GenerateDefaultConvertToMethod("Argb32", "Gray16"); + GenerateDefaultConvertToMethod("Argb32", "Rgb24"); + GenerateDefaultConvertToMethod("Argb32", "Rgba32"); + GenerateDefaultConvertToMethod("Argb32", "Rgb48"); + GenerateDefaultConvertToMethod("Argb32", "Rgba64"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude new file mode 100644 index 0000000000..d433bd5405 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude @@ -0,0 +1,36 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +<#+ + void GenerateDefaultConvertToMethod(string fromPixelType, string toPixelType) + { + #> + + /// + internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=toPixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < count; i++) + { + ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.From<#=fromPixelType#>(sp); + } + } + <#+ + } +#> \ No newline at end of file From f55050bcfbff74c9ed35a8be731a3a637758a515 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 14:22:55 +0200 Subject: [PATCH 058/238] GenerateDefaultSelfConversionMethods --- .../Argb32.PixelOperations.Generated.cs | 5 ++-- .../Argb32.PixelOperations.Generated.tt | 17 +------------- .../Generated/RgbaCompatible.Common.ttinclude | 23 +++++++++++++++++++ 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 507c8cd3ac..e5a2ffc2a2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -19,7 +19,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index 4324211666..a3e944f98c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -13,23 +13,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal class PixelOperations : PixelOperations { - /// - internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# + GenerateDefaultSelfConversionMethods("Argb32"); GenerateDefaultConvertToMethod("Argb32", "Bgr24"); GenerateDefaultConvertToMethod("Argb32", "Bgra32"); GenerateDefaultConvertToMethod("Argb32", "Gray8"); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude index d433bd5405..150607538b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude @@ -11,6 +11,29 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <#+ + void GenerateDefaultSelfConversionMethods(string pixelType) + { + #> + + /// + internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + source.Slice(0, count).CopyTo(destPixels); + } + + /// + internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels, int count) + { + GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + + sourcePixels.Slice(0, count).CopyTo(destPixels); + } + + <#+ + } + void GenerateDefaultConvertToMethod(string fromPixelType, string toPixelType) { #> From 0dedf86b0b403c2da244b40993ae749f9d36b297 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 15:04:15 +0200 Subject: [PATCH 059/238] DRY out PixelOperations generators --- .../Argb32.PixelOperations.Generated.cs | 1 + .../Argb32.PixelOperations.Generated.tt | 12 +-- .../Bgr24.PixelOperations.Generated.cs | 32 ++++---- .../Bgr24.PixelOperations.Generated.tt | 67 +---------------- .../Bgra32.PixelOperations.Generated.cs | 16 ++-- .../Bgra32.PixelOperations.Generated.tt | 67 +---------------- .../Gray16.PixelOperations.Generated.cs | 16 ++-- .../Gray16.PixelOperations.Generated.tt | 67 +---------------- .../Gray8.PixelOperations.Generated.cs | 16 ++-- .../Gray8.PixelOperations.Generated.tt | 67 +---------------- .../Rgb24.PixelOperations.Generated.cs | 16 ++-- .../Rgb24.PixelOperations.Generated.tt | 67 +---------------- .../Rgb48.PixelOperations.Generated.cs | 16 ++-- .../Rgb48.PixelOperations.Generated.tt | 67 +---------------- .../Rgba32.PixelOperations.Generated.cs | 22 +++--- .../Rgba32.PixelOperations.Generated.tt | 73 ++----------------- .../Rgba64.PixelOperations.Generated.cs | 16 ++-- .../Rgba64.PixelOperations.Generated.tt | 67 +---------------- ...ble.Common.ttinclude => _Common.ttinclude} | 15 ++++ 19 files changed, 120 insertions(+), 600 deletions(-) rename src/ImageSharp/PixelFormats/PixelImplementations/Generated/{RgbaCompatible.Common.ttinclude => _Common.ttinclude} (81%) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index e5a2ffc2a2..655c4c3188 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -1,5 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. + // using System; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index a3e944f98c..8c4c6b58af 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -1,4 +1,4 @@ -<#@include file="RgbaCompatible.Common.ttinclude" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> namespace SixLabors.ImageSharp.PixelFormats @@ -14,15 +14,7 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { <# - GenerateDefaultSelfConversionMethods("Argb32"); - GenerateDefaultConvertToMethod("Argb32", "Bgr24"); - GenerateDefaultConvertToMethod("Argb32", "Bgra32"); - GenerateDefaultConvertToMethod("Argb32", "Gray8"); - GenerateDefaultConvertToMethod("Argb32", "Gray16"); - GenerateDefaultConvertToMethod("Argb32", "Rgb24"); - GenerateDefaultConvertToMethod("Argb32", "Rgba32"); - GenerateDefaultConvertToMethod("Argb32", "Rgb48"); - GenerateDefaultConvertToMethod("Argb32", "Rgba64"); + GenerateAllDefaultConversionMethods("Argb32"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index cbfbe70991..5d2ca335e5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Bgr24 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { @@ -43,7 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -60,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -77,7 +79,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -94,7 +96,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -111,7 +113,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -128,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -145,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); @@ -162,7 +164,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - + for (int i = 0; i < count; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt index 0f7bd838ff..56e3bf9ba4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - dp.FromBgr24(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Bgr24 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Bgr24"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index edd702e0e0..1121f43437 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Bgra32 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt index 4c4e10fad0..6563ff9072 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Bgra32 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Bgra32"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index ca0e1fe326..e27f8bc587 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Gray16 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt index 1e500dac54..3db96d70a9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromGray16(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Gray16 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Gray16"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 6950c337d6..26ed91cfff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Gray8 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt index 7c6e2f7675..a65d8f2634 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromGray8(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Gray8 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Gray8"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index 53234cd66e..8a6c6bddc1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgb24 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt index b98e1e4c7c..796cdeb662 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgb24 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Rgb24"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 61d13978ab..1701109edf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgb48 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt index 2ff3125b4c..b8ee99fce1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgb48 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Rgb48"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index ae2ffd6888..fb817a29ae 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgba32 { - - /// + /// /// Provides optimized overrides for bulk operations. - /// - internal partial class PixelOperations + /// + internal partial class PixelOperations : PixelOperations { - /// + + /// internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt index fb8d6db349..0c4a4c0c0a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgba32 { - - /// + /// /// Provides optimized overrides for bulk operations. - /// - internal partial class PixelOperations + /// + internal partial class PixelOperations : PixelOperations { - /// - internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgb48"); - GenerateConvertToMethod("Rgba64"); + GenerateAllDefaultConversionMethods("Rgba32"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index 252068828e..d49fb7ae5e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -2,24 +2,26 @@ // Licensed under the Apache License, Version 2.0. // + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgba64 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// + + /// internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) { GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats sourcePixels.Slice(0, count).CopyTo(destPixels); } - + /// internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) { diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt index 626f2316d3..9409e1573e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt @@ -1,83 +1,20 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> +<#@include file="_Common.ttinclude" #> <#@ output extension=".cs" #> -<# - void GenerateConvertToMethod(string pixelType) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) - { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// namespace SixLabors.ImageSharp.PixelFormats { - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - /// /// Provides optimized overrides for bulk operations. /// public partial struct Rgba64 { - /// /// Provides optimized overrides for bulk operations. /// internal class PixelOperations : PixelOperations { - /// - internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); - - sourcePixels.Slice(0, count).CopyTo(destPixels); - } - <# - GenerateConvertToMethod("Argb32"); - GenerateConvertToMethod("Bgr24"); - GenerateConvertToMethod("Bgra32"); - GenerateConvertToMethod("Gray8"); - GenerateConvertToMethod("Gray16"); - GenerateConvertToMethod("Rgb24"); - GenerateConvertToMethod("Rgba32"); - GenerateConvertToMethod("Rgb48"); + GenerateAllDefaultConversionMethods("Rgba64"); #> } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude similarity index 81% rename from src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude rename to src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index 150607538b..af8c42357e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/RgbaCompatible.Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -5,12 +5,15 @@ <#@ import namespace="System.Collections.Generic" #> // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. + // using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <#+ + static readonly string[] CommonPixelTypeNames = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + void GenerateDefaultSelfConversionMethods(string pixelType) { #> @@ -56,4 +59,16 @@ using System.Runtime.InteropServices; } <#+ } + + void GenerateAllDefaultConversionMethods(string pixelType) + { + GenerateDefaultSelfConversionMethods(pixelType); + + var allOtherPixelTypes = CommonPixelTypeNames.Where(p => p != pixelType); + + foreach (string destPixelType in allOtherPixelTypes) + { + GenerateDefaultConvertToMethod(pixelType, destPixelType); + } + } #> \ No newline at end of file From ed55a1f75b280dd9996f41022b930d8b33f0b904 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 15:17:37 +0200 Subject: [PATCH 060/238] CLA assistant, please wake up! --- tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs index 950434ac32..629b3cdeb3 100644 --- a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs +++ b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs @@ -1,8 +1,9 @@ -using System; -using System.Runtime.CompilerServices; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; - using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers From 3986dedb3cb230a025986a679cc089b454299d11 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 16:43:31 +0200 Subject: [PATCH 061/238] Adapt Span.CopyTo(...) semantics on color conversion API-s --- .../Conversion/ColorSpaceConverter.CieLab.cs | 78 ++-- .../Conversion/ColorSpaceConverter.CieLch.cs | 79 ++-- .../ColorSpaceConverter.CieLchuv.cs | 79 ++-- .../Conversion/ColorSpaceConverter.CieLuv.cs | 79 ++-- .../Conversion/ColorSpaceConverter.CieXyy.cs | 79 ++-- .../Conversion/ColorSpaceConverter.CieXyz.cs | 82 ++-- .../Conversion/ColorSpaceConverter.Cmyk.cs | 79 ++-- .../Conversion/ColorSpaceConverter.Hsl.cs | 79 ++-- .../Conversion/ColorSpaceConverter.Hsv.cs | 79 ++-- .../ColorSpaceConverter.HunterLab.cs | 368 ++++++++--------- .../ColorSpaceConverter.LinearRgb.cs | 371 ++++++++--------- .../Conversion/ColorSpaceConverter.Lms.cs | 356 ++++++++--------- .../Conversion/ColorSpaceConverter.Rgb.cs | 377 +++++++++--------- .../Conversion/ColorSpaceConverter.YCbCr.cs | 351 ++++++++-------- .../Conversion/IChromaticAdaptation.cs | 7 +- .../Conversion/VonKriesChromaticAdaptation.cs | 9 +- src/ImageSharp/Common/Helpers/Guard.cs | 63 ++- .../CieLabAndCieLchConversionTests.cs | 4 +- .../CieLabAndCieLchuvConversionTests.cs | 4 +- .../CieLabAndCieLuvConversionTests.cs | 4 +- .../CieLabAndCieXyyConversionTests.cs | 4 +- .../CieLabAndCmykConversionTests.cs | 4 +- .../Conversion/CieLabAndHslConversionTests.cs | 4 +- .../Conversion/CieLabAndHsvConversionTests.cs | 4 +- .../CieLabAndHunterLabConversionTests.cs | 4 +- .../CieLabAndLinearRgbConversionTests.cs | 4 +- .../Conversion/CieLabAndLmsConversionTests.cs | 4 +- .../Conversion/CieLabAndRgbConversionTests.cs | 4 +- .../CieLabAndYCbCrConversionTests.cs | 4 +- .../CieLchAndCieLuvConversionTests.cs | 4 +- .../CieLchAndCieXyyConversionTests.cs | 4 +- .../Conversion/CieLchAndHslConversionTests.cs | 4 +- .../Conversion/CieLchAndHsvConversionTests.cs | 4 +- .../CieLchAndHunterLabConversionTests.cs | 4 +- .../CieLchAndLinearRgbConversionTests.cs | 4 +- .../Conversion/CieLchAndLmsConversionTests.cs | 4 +- .../Conversion/CieLchAndRgbConversionTests.cs | 4 +- .../CieLchAndYCbCrConversionTests.cs | 4 +- .../CieLchuvAndCieLchConversionTests.cs | 4 +- .../CieLchuvAndCieLuvConversionTests.cs | 4 +- .../CieLchuvAndCmykConversionTests.cs | 4 +- .../CieLuvAndCieXyyConversionTests.cs | 4 +- .../Conversion/CieLuvAndHslConversionTests.cs | 4 +- .../Conversion/CieLuvAndHsvConversionTests.cs | 4 +- .../CieLuvAndHunterLabConversionTests.cs | 4 +- .../CieLuvAndLinearRgbConversionTests.cs | 4 +- .../Conversion/CieLuvAndLmsConversionTests.cs | 4 +- .../Conversion/CieLuvAndRgbConversionTests.cs | 4 +- .../CieLuvAndYCbCrConversionTests.cs | 4 +- .../Conversion/CieXyyAndHslConversionTests.cs | 4 +- .../Conversion/CieXyyAndHsvConversionTests.cs | 4 +- .../CieXyyAndHunterLabConversionTests.cs | 4 +- .../CieXyyAndLinearRgbConversionTests.cs | 4 +- .../Conversion/CieXyyAndLmsConversionTests.cs | 4 +- .../Conversion/CieXyyAndRgbConversionTests.cs | 4 +- .../CieXyyAndYCbCrConversionTests.cs | 4 +- .../CieXyzAndCieLabConversionTest.cs | 4 +- .../CieXyzAndCieLchConversionTests.cs | 4 +- .../CieXyzAndCieLchuvConversionTests.cs | 4 +- .../CieXyzAndCieLuvConversionTest.cs | 4 +- .../CieXyzAndCieXyyConversionTest.cs | 4 +- .../Conversion/CieXyzAndHslConversionTests.cs | 4 +- .../Conversion/CieXyzAndHsvConversionTests.cs | 4 +- .../CieXyzAndHunterLabConversionTest.cs | 6 +- .../Conversion/CieXyzAndLmsConversionTest.cs | 4 +- .../CieXyzAndYCbCrConversionTests.cs | 4 +- .../CmykAndCieLchConversionTests.cs | 4 +- .../CmykAndCieLuvConversionTests.cs | 4 +- .../CmykAndCieXyyConversionTests.cs | 4 +- .../CmykAndCieXyzConversionTests.cs | 4 +- .../Conversion/CmykAndHslConversionTests.cs | 4 +- .../Conversion/CmykAndHsvConversionTests.cs | 4 +- .../CmykAndHunterLabConversionTests.cs | 4 +- .../Conversion/CmykAndYCbCrConversionTests.cs | 4 +- .../Conversion/RgbAndCieXyzConversionTest.cs | 8 +- .../Conversion/RgbAndCmykConversionTest.cs | 4 +- .../Conversion/RgbAndHslConversionTest.cs | 4 +- .../Conversion/RgbAndHsvConversionTest.cs | 4 +- .../Conversion/RgbAndYCbCrConversionTest.cs | 4 +- .../VonKriesChromaticAdaptationTests.cs | 2 +- tests/ImageSharp.Tests/Helpers/GuardTests.cs | 32 ++ 81 files changed, 1489 insertions(+), 1414 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 3ce14cdea4..3c197673d3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -37,10 +37,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -103,10 +103,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -136,10 +136,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -171,10 +171,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -203,10 +203,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -236,10 +236,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -268,10 +268,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -301,10 +301,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -334,10 +334,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -367,10 +367,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -400,10 +400,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -433,10 +433,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 3c9e6658cd..0a8607e3bc 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -37,10 +38,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -70,10 +71,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -103,10 +104,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -136,10 +137,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -169,10 +170,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -201,10 +202,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -234,10 +235,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -267,10 +268,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -300,10 +301,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -333,10 +334,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -366,10 +367,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -399,10 +400,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -432,10 +433,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 01de794885..3a779ee722 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -35,10 +36,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -68,10 +69,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -103,10 +104,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -136,10 +137,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -169,10 +170,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -202,10 +203,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -235,10 +236,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -268,10 +269,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -301,10 +302,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -334,10 +335,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -367,10 +368,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -400,10 +401,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -432,10 +433,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index 0b469e065f..90eb8e34d7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -31,10 +32,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -63,10 +64,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -130,10 +131,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -165,10 +166,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -229,10 +230,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -261,10 +262,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -293,10 +294,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -325,10 +326,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -357,10 +358,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -389,10 +390,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -421,10 +422,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index b77f48325f..d03c10a01d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -159,10 +160,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -192,10 +193,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -225,10 +226,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -258,10 +259,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -291,10 +292,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -324,10 +325,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -357,10 +358,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 8963ad495a..fada6d9c59 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -17,7 +18,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion private static readonly CieLuvToCieXyzConverter CieLuvToCieXyzConverter = new CieLuvToCieXyzConverter(); - private static readonly HunterLabToCieXyzConverter HunterLabToCieXyzConverter = new HunterLabToCieXyzConverter(); + private static readonly HunterLabToCieXyzConverter + HunterLabToCieXyzConverter = new HunterLabToCieXyzConverter(); private LinearRgbToCieXyzConverter linearRgbToCieXyzConverter; @@ -40,10 +42,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -75,10 +77,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -110,10 +112,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -145,10 +147,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -177,10 +179,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -211,10 +213,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -245,10 +247,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -279,10 +281,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -314,10 +316,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -350,10 +352,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -382,10 +384,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -415,10 +417,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -449,10 +451,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index 6f8fe61469..b798516359 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -164,10 +165,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -230,10 +231,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -263,10 +264,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -296,10 +297,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -329,10 +330,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -362,10 +363,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index 106e8956f1..a7080b9749 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -164,10 +165,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -230,10 +231,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -263,10 +264,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -296,10 +297,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -329,10 +330,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -362,10 +363,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index 8b4e29215c..a2121203c1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -164,10 +165,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -230,10 +231,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -263,10 +264,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -296,10 +297,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -329,10 +330,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -362,10 +363,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index b3286a9cc4..e5996c238e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -12,26 +12,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// public partial class ColorSpaceConverter { - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -44,26 +33,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -76,26 +54,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -108,26 +75,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -140,26 +96,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -172,29 +117,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint); - - // Conversion - return this.cieXyzToHunterLabConverter.Convert(adapted); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -207,26 +138,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -240,14 +160,24 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - /// Converts a into a + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsl color) + /// The span to the source colors + /// The span to the destination colors + public void Convert(ReadOnlySpan source, Span destination) { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } } /// @@ -255,180 +185,250 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i); dp = this.ToHunterLab(sp); } } /// - /// Converts a into a + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsv color) + /// The span to the source colors + /// The span to the destination colors + public void Convert(ReadOnlySpan source, Span destination) { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } } /// - /// Performs the bulk conversion from into + /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i); dp = this.ToHunterLab(sp); } } /// - /// Converts a into a + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in LinearRgb color) + /// The span to the source colors + /// The span to the destination colors + public void Convert(ReadOnlySpan source, Span destination) { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } } /// - /// Performs the bulk conversion from into + /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i); dp = this.ToHunterLab(sp); } } /// - /// Converts a into a + /// Converts a into a /// /// The color to convert. /// The - public HunterLab ToHunterLab(in Lms color) + public HunterLab ToHunterLab(in CieLab color) { var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } /// - /// Performs the bulk conversion from into + /// Converts a into a /// - /// The span to the source colors - /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieLch color) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - for (int i = 0; i < count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); } /// - /// Converts a into a + /// Converts a into a /// /// The color to convert. /// The - public HunterLab ToHunterLab(in Rgb color) + public HunterLab ToHunterLab(in CieXyy color) { var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } /// - /// Performs the bulk conversion from into + /// Converts a into a /// - /// The span to the source colors - /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieXyz color) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + // Adaptation + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint); - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + // Conversion + return this.cieXyzToHunterLabConverter.Convert(adapted); + } - for (int i = 0; i < count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Cmyk color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); } /// - /// Converts a into a + /// Converts a into a /// /// The color to convert. /// The - public HunterLab ToHunterLab(in YCbCr color) + public HunterLab ToHunterLab(in Hsl color) { var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } /// - /// Performs the bulk conversion from into + /// Converts a into a /// - /// The span to the source colors - /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Hsv color) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in LinearRgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - for (int i = 0; i < count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Rgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in YCbCr color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index 98943c034a..eef626be2f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -15,26 +16,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly RgbToLinearRgbConverter RgbToLinearRgbConverter = new RgbToLinearRgbConverter(); - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -47,26 +37,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -79,26 +58,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -111,26 +79,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -143,26 +100,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -175,29 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); - - // Conversion - return this.cieXyzToLinearRgbConverter.Convert(adapted); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -210,26 +142,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Cmyk color) - { - var rgb = this.ToRgb(color); - return this.ToLinearRgb(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -242,26 +163,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Hsl color) - { - var rgb = this.ToRgb(color); - return this.ToLinearRgb(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -274,26 +184,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Hsv color) - { - var rgb = this.ToRgb(color); - return this.ToLinearRgb(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -306,26 +205,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -338,26 +226,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -370,26 +247,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Rgb color) - { - // Conversion - return RgbToLinearRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -402,26 +268,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in YCbCr color) - { - var rgb = this.ToRgb(color); - return this.ToLinearRgb(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -433,5 +288,151 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToLinearRgb(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieXyz color) + { + // Adaptation + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); + + // Conversion + return this.cieXyzToLinearRgbConverter.Convert(adapted); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Cmyk color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Hsl color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Hsv color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Rgb color) + { + // Conversion + return RgbToLinearRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in YCbCr color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index ffd0f88d11..3b8638f7d2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -12,26 +12,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// public partial class ColorSpaceConverter { - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -44,26 +33,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -76,26 +54,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -108,26 +75,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -140,26 +96,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -172,22 +117,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color); - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -200,26 +138,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -232,26 +159,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsl color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -264,26 +180,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -296,26 +201,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -328,26 +222,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in LinearRgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -360,26 +243,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Rgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -392,26 +264,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in YCbCr color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -423,5 +284,144 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToLms(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color); + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Cmyk color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Hsl color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Hsv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in LinearRgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Rgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in YCbCr color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index cd40c966b1..fc5665e5c1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -15,26 +16,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly LinearRgbToRgbConverter LinearRgbToRgbConverter = new LinearRgbToRgbConverter(); - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -47,26 +37,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -79,26 +58,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -111,26 +79,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -143,26 +100,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -175,29 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyz color) - { - // Conversion - var linear = this.ToLinearRgb(color); - - // Compand - return this.ToRgb(linear); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -210,26 +142,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Cmyk color) - { - // Conversion - return CmykAndRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -242,26 +163,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Hsv color) - { - // Conversion - return HsvAndRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -274,26 +184,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Hsl color) - { - // Conversion - return HslAndRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -306,26 +205,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -338,26 +226,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in LinearRgb color) - { - // Conversion - return LinearRgbToRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -370,26 +247,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -402,29 +268,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in YCbCr color) - { - // Conversion - Rgb rgb = YCbCrAndRgbConverter.Convert(color); - - // Adaptation - return this.Adapt(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -436,5 +288,154 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToRgb(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieXyz color) + { + // Conversion + var linear = this.ToLinearRgb(color); + + // Compand + return this.ToRgb(linear); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Cmyk color) + { + // Conversion + return CmykAndRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Hsv color) + { + // Conversion + return HsvAndRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Hsl color) + { + // Conversion + return HslAndRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in LinearRgb color) + { + // Conversion + return LinearRgbToRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in YCbCr color) + { + // Conversion + Rgb rgb = YCbCrAndRgbConverter.Convert(color); + + // Adaptation + return this.Adapt(rgb); + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 38e6d5fae0..5780f4f545 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -15,27 +16,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly YCbCrAndRgbConverter YCbCrAndRgbConverter = new YCbCrAndRgbConverter(); - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -48,27 +37,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -81,27 +58,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -114,27 +79,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -147,27 +100,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyz color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -180,27 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Cmyk color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -213,27 +142,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Hsl color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -246,27 +163,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Hsv color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -279,27 +184,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -312,27 +205,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in LinearRgb color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -345,27 +226,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -378,22 +247,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -405,5 +267,144 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToYCbCr(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieXyz color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Cmyk color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Hsl color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Hsv color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in LinearRgb color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs index 1b14c6413e..69877d8b55 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs @@ -30,7 +30,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the destination colors. /// The source white point. /// The destination white point. - /// The number of colors to convert. - void Transform(Span source, Span destination, CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint, int count); + void Transform( + ReadOnlySpan source, + Span destination, + CieXyz sourceWhitePoint, + in CieXyz destinationWhitePoint); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index 9b200b8736..85a36331b2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -65,9 +65,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - public void Transform(Span source, Span destination, CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint, int count) + public void Transform( + ReadOnlySpan source, + Span destination, + CieXyz sourceWhitePoint, + in CieXyz destinationWhitePoint) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; if (sourceWhitePoint.Equals(destinationWhitePoint)) { diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index 34ba544726..ef928c2800 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp { @@ -19,6 +20,7 @@ namespace SixLabors.ImageSharp /// The target object, which cannot be null. /// The name of the parameter that is to be checked. /// is null + [MethodImpl(InliningOptions.ShortMethod)] public static void NotNull(T value, string parameterName) where T : class { @@ -35,6 +37,7 @@ namespace SixLabors.ImageSharp /// Name of the parameter. /// is null. /// is empty or contains only blanks. + [MethodImpl(InliningOptions.ShortMethod)] public static void NotNullOrWhiteSpace(string value, string parameterName) { if (value is null) @@ -56,6 +59,7 @@ namespace SixLabors.ImageSharp /// Name of the parameter. /// is null. /// is empty. + [MethodImpl(InliningOptions.ShortMethod)] public static void NotNullOrEmpty(ICollection value, string parameterName) { if (value is null) @@ -79,6 +83,7 @@ namespace SixLabors.ImageSharp /// /// is greater than the maximum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeLessThan(TValue value, TValue max, string parameterName) where TValue : IComparable { @@ -99,6 +104,7 @@ namespace SixLabors.ImageSharp /// /// is greater than the maximum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName) where TValue : IComparable { @@ -119,6 +125,7 @@ namespace SixLabors.ImageSharp /// /// is less than the minimum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeGreaterThan(TValue value, TValue min, string parameterName) where TValue : IComparable { @@ -141,6 +148,7 @@ namespace SixLabors.ImageSharp /// /// is less than the minimum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName) where TValue : IComparable { @@ -162,6 +170,7 @@ namespace SixLabors.ImageSharp /// /// is less than the minimum value of greater than the maximum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName) where TValue : IComparable { @@ -181,6 +190,7 @@ namespace SixLabors.ImageSharp /// /// is false /// + [MethodImpl(InliningOptions.ShortMethod)] public static void IsTrue(bool target, string parameterName, string message) { if (!target) @@ -199,6 +209,7 @@ namespace SixLabors.ImageSharp /// /// is true /// + [MethodImpl(InliningOptions.ShortMethod)] public static void IsFalse(bool target, string parameterName, string message) { if (target) @@ -217,6 +228,7 @@ namespace SixLabors.ImageSharp /// /// has less than items /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName) { if (source.Length < minLength) @@ -225,6 +237,26 @@ namespace SixLabors.ImageSharp } } + /// + /// Verifies that the 'destination' span is not shorter than 'source'. + /// + /// The source element type + /// The destination element type + /// The source span + /// The destination span + /// The name of the argument for 'destination' + [MethodImpl(InliningOptions.ShortMethod)] + public static void DestinationShouldNotBeTooShort( + ReadOnlySpan source, + Span destination, + string destinationParamName) + { + if (destination.Length < source.Length) + { + throw new ArgumentException($"Destination span is too short!", destinationParamName); + } + } + /// /// Verifies, that the `source` span has the length of 'minLength', or longer. /// @@ -235,6 +267,7 @@ namespace SixLabors.ImageSharp /// /// has less than items /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName) { if (source.Length < minLength) @@ -255,7 +288,7 @@ namespace SixLabors.ImageSharp /// The destination parameter name /// The minimum length public static void SpansMustBeSizedAtLeast( - Span source, + ReadOnlySpan source, string sourceParamName, Span dest, string destParamName, @@ -265,26 +298,16 @@ namespace SixLabors.ImageSharp MustBeSizedAtLeast(dest, minLength, destParamName); } - /// - /// Verifies that the given 'source' and 'dest' spans are at least of 'minLength' size. - /// Throwing an if the condition is not met. - /// - /// The source element type - /// The destination element type - /// The source span - /// The source parameter name - /// The destination span - /// The destination parameter name - /// The minimum length - public static void SpansMustBeSizedAtLeast( - ReadOnlySpan source, - string sourceParamName, - Span dest, - string destParamName, - int minLength) + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentException(string message, string parameterName) { - MustBeSizedAtLeast(source, minLength, sourceParamName); - MustBeSizedAtLeast(dest, minLength, destParamName); + throw new ArgumentException(message, parameterName); + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentNullException(string message) + { + throw new ArgumentException(message); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs index eb9a50d185..38c0c21bc9 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs index 7fb5770ddb..96628977fe 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs index 14a1c6fd37..39011bb292 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs index 9a42a9d47d..f7dc365b81 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs index 944fab574e..43300ab88c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs index 836be1bf27..4ab309fe14 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs index fb1982bfc8..e7ff34f494 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs index 7e3c4251bf..844cda4760 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs index a43f0095d7..74ed180f38 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs index 62d08263a6..a3db00e804 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs index 1b30412752..fc202ccc96 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs index 53d33af2b1..3e481d4f64 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs index e465757ef7..078ba44daf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs index 18b8a47397..a65f618835 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs index d00a164c08..49990fb908 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs index d3ff04a759..924b45b4a0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs index 852e56110b..0991657310 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs index 80b72cb2c2..a7a819d1f7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs index 314734ff2e..b83b861be8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs index 389528dcd3..932fdc4105 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs index a2bd7eadc7..4d04418d99 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs index e7f511bab1..3cdaa42792 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs index 3bc4fd519b..6829c62b50 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs index f3940e4d14..0c62ffcc31 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs index 61bfe79634..3b41204f7c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs index 7bc430aa37..bfc0d2ecf1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs index 23cc5082c4..f11b17fff3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs index 04699bde46..de2329c2ec 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs index 98914a6b92..3a1bd10c41 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs index 306d60b531..f3881f10f7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs index 21cf08dede..644f4577bf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs index 8c07c38d60..41b9dba091 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs index fb415f43ba..5b36beaab9 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs index 3c8aee807a..da77378759 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs index 1fcbb75cb2..96d14c98a6 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs index 8c45378ed4..0339730945 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs index 67ec26f6d4..fb0e06e6bb 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs index e309e2d555..5bbcd90875 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs index 3e33f05192..1ee84ef2e5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs index 746e37c0e6..49b99b7052 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieLab(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs index 89d78ece1f..77f0c69699 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs index fbd602d9a0..24e134d732 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs index c0856a2bc1..761b9851e3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieLuv(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs index 3f5ea4cfd8..2b0350cea1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs index 8443722641..cd1c9f2c3e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs index 327d660c6c..8112f6a198 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs index d162940151..2fed3e9c55 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToHunterLab(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs index 484d302e9a..75634eb51e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToLms(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs index eacdc7ffba..9ea890f101 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs index 4a0c88c841..dbb0c6e200 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs index 2131ba630b..5fcc59090b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs index ac93aaf25b..7ff80c170b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs index cbb8f7dc4e..8017302059 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs index 1c9ad170d3..3464fdbbde 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs index 6fd1ba88ec..26af5ddd30 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs index e92ac2e528..dc40ee518e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs index 575122661a..00569ced2e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs index a3b0cbd953..8a2cd1159e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs index 2b03ee9883..b01e3a854c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs index 22f5c6d514..502df84133 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs index e84ce97237..9adc94af7c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs index f5c7dbae66..94879eee7a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs index cfd48b694d..b1427f4d5f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion Span actualSpan = new CieXyz[5]; - adaptation.Transform(inputSpan, actualSpan, sourceWhitePoint, destinationWhitePoint, inputSpan.Length); + adaptation.Transform(inputSpan, actualSpan, sourceWhitePoint, destinationWhitePoint); for (int i = 0; i < inputSpan.Length; i++) { diff --git a/tests/ImageSharp.Tests/Helpers/GuardTests.cs b/tests/ImageSharp.Tests/Helpers/GuardTests.cs index 0d1bb5ce9f..b847e581f5 100644 --- a/tests/ImageSharp.Tests/Helpers/GuardTests.cs +++ b/tests/ImageSharp.Tests/Helpers/GuardTests.cs @@ -3,7 +3,10 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Linq; + using Xunit; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Helpers { @@ -16,6 +19,35 @@ namespace SixLabors.ImageSharp.Tests.Helpers { } + [Theory] + [InlineData(0, 0)] + [InlineData(0, 1)] + [InlineData(0, 42)] + [InlineData(1, 1)] + [InlineData(10, 42)] + [InlineData(42, 42)] + public void DestinationShouldNotBeTooShort_WhenOk(int sourceLength, int destLength) + { + ReadOnlySpan source = new int[sourceLength]; + Span dest = new float[destLength]; + + Guard.DestinationShouldNotBeTooShort(source, dest, nameof(dest)); + } + + [Theory] + [InlineData(1, 0)] + [InlineData(42, 41)] + public void DestinationShouldNotBeTooShort_WhenThrows(int sourceLength, int destLength) + { + Assert.ThrowsAny( + () => + { + ReadOnlySpan source = new int[sourceLength]; + Span dest = new float[destLength]; + Guard.DestinationShouldNotBeTooShort(source, dest, nameof(dest)); + }); + } + /// /// Tests that the method throws when the argument is null. /// From cf9476be963425b6c40b02e6b3a1307a519f294f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 16:50:15 +0200 Subject: [PATCH 062/238] Improve Guard --- src/ImageSharp/Common/Helpers/Guard.cs | 73 ++++++++++++-------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index ef928c2800..cd53e3d69a 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -21,12 +21,13 @@ namespace SixLabors.ImageSharp /// The name of the parameter that is to be checked. /// is null [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void NotNull(T value, string parameterName) where T : class { if (value is null) { - throw new ArgumentNullException(parameterName); + ThrowArgumentNullException(parameterName); } } @@ -38,16 +39,17 @@ namespace SixLabors.ImageSharp /// is null. /// is empty or contains only blanks. [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void NotNullOrWhiteSpace(string value, string parameterName) { if (value is null) { - throw new ArgumentNullException(parameterName); + ThrowArgumentNullException(parameterName); } if (string.IsNullOrWhiteSpace(value)) { - throw new ArgumentException("Must not be empty or whitespace.", parameterName); + ThrowArgumentException("Must not be empty or whitespace.", parameterName); } } @@ -60,16 +62,17 @@ namespace SixLabors.ImageSharp /// is null. /// is empty. [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void NotNullOrEmpty(ICollection value, string parameterName) { if (value is null) { - throw new ArgumentNullException(parameterName); + ThrowArgumentNullException(parameterName); } if (value.Count == 0) { - throw new ArgumentException("Must not be empty.", parameterName); + ThrowArgumentException("Must not be empty.", parameterName); } } @@ -84,12 +87,13 @@ namespace SixLabors.ImageSharp /// is greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeLessThan(TValue value, TValue max, string parameterName) where TValue : IComparable { if (value.CompareTo(max) >= 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}."); } } @@ -105,12 +109,13 @@ namespace SixLabors.ImageSharp /// is greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName) where TValue : IComparable { if (value.CompareTo(max) > 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}."); } } @@ -126,12 +131,13 @@ namespace SixLabors.ImageSharp /// is less than the minimum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeGreaterThan(TValue value, TValue min, string parameterName) where TValue : IComparable { if (value.CompareTo(min) <= 0) { - throw new ArgumentOutOfRangeException( + ThrowArgumentOutOfRangeException( parameterName, $"Value {value} must be greater than {min}."); } @@ -149,12 +155,13 @@ namespace SixLabors.ImageSharp /// is less than the minimum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName) where TValue : IComparable { if (value.CompareTo(min) < 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}."); } } @@ -171,12 +178,13 @@ namespace SixLabors.ImageSharp /// is less than the minimum value of greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName) where TValue : IComparable { if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}."); } } @@ -191,11 +199,12 @@ namespace SixLabors.ImageSharp /// is false /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void IsTrue(bool target, string parameterName, string message) { if (!target) { - throw new ArgumentException(message, parameterName); + ThrowArgumentException(message, parameterName); } } @@ -210,11 +219,12 @@ namespace SixLabors.ImageSharp /// is true /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void IsFalse(bool target, string parameterName, string message) { if (target) { - throw new ArgumentException(message, parameterName); + ThrowArgumentException(message, parameterName); } } @@ -229,11 +239,12 @@ namespace SixLabors.ImageSharp /// has less than items /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName) { if (source.Length < minLength) { - throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName); + ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName); } } @@ -246,6 +257,7 @@ namespace SixLabors.ImageSharp /// The destination span /// The name of the argument for 'destination' [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void DestinationShouldNotBeTooShort( ReadOnlySpan source, Span destination, @@ -253,7 +265,7 @@ namespace SixLabors.ImageSharp { if (destination.Length < source.Length) { - throw new ArgumentException($"Destination span is too short!", destinationParamName); + ThrowArgumentException($"Destination span is too short!", destinationParamName); } } @@ -268,46 +280,31 @@ namespace SixLabors.ImageSharp /// has less than items /// [MethodImpl(InliningOptions.ShortMethod)] + [DebuggerStepThrough] public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName) { if (source.Length < minLength) { - throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName); + ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName); } } - /// - /// Verifies that the given 'source' and 'dest' spans are at least of 'minLength' size. - /// Throwing an if the condition is not met. - /// - /// The source element type - /// The destination element type - /// The source span - /// The source parameter name - /// The destination span - /// The destination parameter name - /// The minimum length - public static void SpansMustBeSizedAtLeast( - ReadOnlySpan source, - string sourceParamName, - Span dest, - string destParamName, - int minLength) + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentException(string message, string parameterName) { - MustBeSizedAtLeast(source, minLength, sourceParamName); - MustBeSizedAtLeast(dest, minLength, destParamName); + throw new ArgumentException(message, parameterName); } [MethodImpl(InliningOptions.ColdPath)] - private static void ThrowArgumentException(string message, string parameterName) + private static void ThrowArgumentOutOfRangeException(string parameterName, string message) { - throw new ArgumentException(message, parameterName); + throw new ArgumentOutOfRangeException(parameterName, message); } [MethodImpl(InliningOptions.ColdPath)] - private static void ThrowArgumentNullException(string message) + private static void ThrowArgumentNullException(string parameterName) { - throw new ArgumentException(message); + throw new ArgumentNullException(parameterName); } } } From ebff0a51e19d6d122d5c7a709ed511d7112f9233 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 17:03:06 +0200 Subject: [PATCH 063/238] Span.CopyTo(...) semantics for bulk Vecto4 conversion in PixelOperations --- .../Decoder/JpegImagePostProcessor.cs | 3 +- .../PixelFormats/PixelBlender{TPixel}.cs | 12 ++++---- .../Rgba32.PixelOperations.cs | 25 ++++++++--------- .../RgbaVector.PixelOperations.cs | 20 +++++++------ .../PixelFormats/PixelOperations{TPixel}.cs | 28 ++++++++----------- .../Convolution/Convolution2DProcessor.cs | 4 +-- .../Convolution/Convolution2PassProcessor.cs | 4 +-- .../Convolution/ConvolutionProcessor.cs | 4 +-- .../Dithering/PaletteDitherProcessorBase.cs | 2 +- .../FrameQuantizerBase{TPixel}.cs | 2 +- .../PaletteFrameQuantizer{TPixel}.cs | 2 +- .../Processors/Transforms/ResizeProcessor.cs | 4 +-- .../PixelFormats/PixelOperationsTests.cs | 10 +++---- .../TestUtilities/TestImageExtensions.cs | 4 +-- 14 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index eb618dff0e..6bd287732d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -159,7 +159,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Span destRow = destination.GetPixelRowSpan(yy); - PixelOperations.Instance.FromVector4(this.rgbaBuffer.GetSpan(), destRow, destination.Width); + // TODO: Investigate if slicing is actually necessary + PixelOperations.Instance.FromVector4(this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); } } } diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 48a83335a0..6c24ce05b2 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -93,12 +93,12 @@ namespace SixLabors.ImageSharp.PixelFormats Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4(background, backgroundSpan); + PixelOperations.Instance.ToScaledVector4(source, sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4(destinationSpan, destination); } } @@ -127,12 +127,12 @@ namespace SixLabors.ImageSharp.PixelFormats Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4(background, backgroundSpan); + PixelOperations.Instance.ToScaledVector4(source, sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4(destinationSpan, destination); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index 4da9f101bc..c25baa4512 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -19,13 +19,11 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations : PixelOperations { /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); - sourceColors = sourceColors.Slice(0, count); - destinationVectors = destinationVectors.Slice(0, count); + destinationVectors = destinationVectors.Slice(0, sourceColors.Length); SimdUtils.BulkConvertByteToNormalizedFloat( MemoryMarshal.Cast(sourceColors), @@ -33,12 +31,11 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); - sourceVectors = sourceVectors.Slice(0, count); - destinationColors = destinationColors.Slice(0, count); + destinationColors = destinationColors.Slice(0, sourceVectors.Length); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( MemoryMarshal.Cast(sourceVectors), @@ -46,15 +43,17 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - this.ToVector4(sourceColors, destinationVectors, count); + this.ToVector4(sourceColors, destinationVectors); } /// - internal override void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromScaledVector4( + ReadOnlySpan sourceVectors, + Span destinationColors) { - this.FromVector4(sourceVectors, destinationColors, count); + this.FromVector4(sourceVectors, destinationColors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index ae64ed4de3..d1f3263659 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -18,23 +18,27 @@ namespace SixLabors.ImageSharp.PixelFormats internal class PixelOperations : PixelOperations { /// - internal override void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal override void FromScaledVector4( + ReadOnlySpan sourceVectors, + Span destinationColors) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); - MemoryMarshal.Cast(sourceVectors).Slice(0, count).CopyTo(destinationColors); + MemoryMarshal.Cast(sourceVectors).CopyTo(destinationColors); } /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) - => this.ToVector4(sourceColors, destinationVectors, count); + internal override void ToScaledVector4( + ReadOnlySpan sourceColors, + Span destinationVectors) + => this.ToVector4(sourceColors, destinationVectors); /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); - MemoryMarshal.Cast(sourceColors).Slice(0, count).CopyTo(destinationVectors); + MemoryMarshal.Cast(sourceColors).CopyTo(destinationVectors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index af7690c62d..e6ccaf914d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -26,15 +26,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The to the source vectors. /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal virtual void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourceVectors.Length; i++) { ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destRef, i); @@ -47,15 +46,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The to the source colors. /// The to the destination vectors. - /// The number of pixels to convert. - internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourceColors.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); ref Vector4 dp = ref Unsafe.Add(ref destRef, i); @@ -68,15 +66,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The to the source vectors. /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal virtual void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourceVectors.Length; i++) { ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destRef, i); @@ -89,15 +86,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The to the source colors. /// The to the destination vectors. - /// The number of pixels to convert. - internal virtual void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal virtual void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourceColors.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); ref Vector4 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index df4df64cad..90049a994d 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -75,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); + PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 03447531ef..f38f16f1a9 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); + PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index a42b777feb..d1b3f0ccf8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -59,14 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); + PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs index a1bbe72733..fd93801092 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering { this.Palette = palette ?? throw new ArgumentNullException(nameof(palette)); this.paletteVector = new Vector4[this.Palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.Palette, this.paletteVector, this.Palette.Length); + PixelOperations.Instance.ToScaledVector4(this.Palette, this.paletteVector); } /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index 6e594f223e..bc0ed0eab1 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Collect the palette. Required before the second pass runs. TPixel[] palette = this.GetPalette(); this.paletteVector = new Vector4[palette.Length]; - PixelOperations.Instance.ToScaledVector4(palette, this.paletteVector, palette.Length); + PixelOperations.Instance.ToScaledVector4(palette, this.paletteVector); var quantizedFrame = new QuantizedFrame(image.MemoryAllocator, width, height, palette); if (this.Dither) diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index cdf3514e2d..625400413d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors)); this.palette = colors; this.paletteVector = new Vector4[this.palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector, this.palette.Length); + PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 5bd61aab19..05c4464f18 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span sourceRow = source.GetPixelRowSpan(y); Span tempRowSpan = tempRowBuffer.Span; - PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length); + PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan); Vector4Utils.Premultiply(tempRowSpan); ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; @@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.FromVector4(tempRowSpan, targetRowSpan, tempRowSpan.Length); + PixelOperations.Instance.FromVector4(tempRowSpan, targetRowSpan); } }); } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 958c4744ad..0082e6c0ec 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { this.Measure( times, - () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count)); + () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan())); } } } @@ -367,7 +367,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromVector4(s, d.GetSpan()) ); } @@ -381,7 +381,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromScaledVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromScaledVector4(s, d.GetSpan()) ); } @@ -417,7 +417,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToVector4(s, d.GetSpan(), count) + (s, d) => Operations.ToVector4(s, d.GetSpan()) ); } @@ -431,7 +431,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) + (s, d) => Operations.ToScaledVector4(s, d.GetSpan()) ); } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 78927dece3..f055ce5480 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests { Span pixelSpan = frame.GetPixelSpan(); - PixelOperations.Instance.ToScaledVector4(pixelSpan, tempSpan, pixelSpan.Length); + PixelOperations.Instance.ToScaledVector4(pixelSpan, tempSpan); for (int i = 0; i < tempSpan.Length; i++) { @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests v.W = 1F; } - PixelOperations.Instance.FromScaledVector4(tempSpan, pixelSpan, pixelSpan.Length); + PixelOperations.Instance.FromScaledVector4(tempSpan, pixelSpan); } } }); From 6e52e99f3725fbf89ac1b5fc288f18ac70370d1d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 17:25:12 +0200 Subject: [PATCH 064/238] Adapt Span.CopyTo(...) semantics for all pixel conversion methods in PixelOperations --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 2 +- .../Encoder/YCbCrForwardConverter{TPixel}.cs | 4 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 8 +- src/ImageSharp/ImageFrame{TPixel}.cs | 2 +- .../Argb32.PixelOperations.Generated.cs | 60 ++--- .../Bgr24.PixelOperations.Generated.cs | 60 ++--- .../Bgra32.PixelOperations.Generated.cs | 60 ++--- .../Gray16.PixelOperations.Generated.cs | 60 ++--- .../Gray8.PixelOperations.Generated.cs | 60 ++--- .../Rgb24.PixelOperations.Generated.cs | 60 ++--- .../Rgb48.PixelOperations.Generated.cs | 60 ++--- .../Rgba32.PixelOperations.Generated.cs | 60 ++--- .../Rgba64.PixelOperations.Generated.cs | 60 ++--- .../Generated/_Common.ttinclude | 18 +- .../PixelOperations{TPixel}.Generated.cs | 234 ++++++++---------- .../PixelOperations{TPixel}.Generated.tt | 26 +- .../PixelFormats/PixelOperations{TPixel}.cs | 20 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 2 +- .../Color/Bulk/FromVector4.cs | 4 +- .../Color/Bulk/ToVector4.cs | 4 +- .../PixelBlenders/PorterDuffBulkVsPixel.cs | 6 +- .../ImageComparison/ExactImageComparer.cs | 4 +- .../ImageComparison/TolerantImageComparer.cs | 4 +- .../ReferenceCodecs/SystemDrawingBridge.cs | 6 +- 24 files changed, 433 insertions(+), 451 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index f00a6b61e3..7db347aa65 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan, length); + PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs index 311ffed24b..b2a8fccf4a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// On-stack worker struct to efficiently encapsulate the TPixel -> Rgb24 -> YCbCr conversion chain of 8x8 pixel blocks. /// /// The pixel type to work on - internal struct YCbCrForwardConverter + internal ref struct YCbCrForwardConverter where TPixel : struct, IPixel { /// @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder this.pixelBlock.LoadAndStretchEdges(pixels, x, y); Span rgbSpan = this.rgbBlock.AsSpanUnsafe(); - PixelOperations.Instance.ToRgb24(this.pixelBlock.AsSpanUnsafe(), rgbSpan, 64); + PixelOperations.Instance.ToRgb24(this.pixelBlock.AsSpanUnsafe(), rgbSpan); ref float yBlockStart = ref Unsafe.As(ref this.Y); ref float cbBlockStart = ref Unsafe.As(ref this.Cb); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index cf7b7b2c66..84f7cb6cc4 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -327,7 +327,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span luminanceSpan = luminanceBuffer.GetSpan(); ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan); - PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan, rowSpan.Length); + PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) @@ -370,7 +370,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4) @@ -430,7 +430,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length); + PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) @@ -453,7 +453,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbSpan = rgbBuffer.GetSpan(); ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan); - PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan, rowSpan.Length); + PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index ecf9e13ceb..25c517d442 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -296,7 +296,7 @@ namespace SixLabors.ImageSharp { Span sourceRow = this.GetPixelRowSpan(y); Span targetRow = target.GetPixelRowSpan(y); - PixelOperations.Instance.To(sourceRow, targetRow, sourceRow.Length); + PixelOperations.Instance.To(sourceRow, targetRow); } }); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 655c4c3188..26e85e043d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromArgb32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 5d2ca335e5..080a25429b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgr24(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 1121f43437..6a1bb6cdc3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromBgra32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index e27f8bc587..cbb9df4459 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray16(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray16(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 26ed91cfff..b88f18e8de 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray8(ReadOnlySpan source, Span destPixels, int count) + internal override void FromGray8(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index 8a6c6bddc1..49c56f4fa2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb24(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 1701109edf..cda6dbf72c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgb48(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index fb817a29ae..ab264f8701 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index d49fb7ae5e..4bc6b101ae 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -22,31 +22,31 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal override void FromRgba64(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i); @@ -56,14 +56,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); @@ -73,14 +73,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); @@ -90,14 +90,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i); @@ -107,14 +107,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i); @@ -124,14 +124,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); @@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); @@ -158,14 +158,14 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index af8c42357e..176075a40f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -19,19 +19,19 @@ using System.Runtime.InteropServices; #> /// - internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels, int count) + internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); - source.Slice(0, count).CopyTo(destPixels); + source.CopyTo(destPixels); } /// - internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels, int count) + internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - sourcePixels.Slice(0, count).CopyTo(destPixels); + sourcePixels.CopyTo(destPixels); } <#+ @@ -42,14 +42,14 @@ using System.Runtime.InteropServices; #> /// - internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels, int count) + internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref <#=toPixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i); ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index f1d426389b..1cbf487d76 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -11,19 +11,18 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromArgb32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromArgb32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -33,7 +32,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -42,23 +41,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromArgb32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -68,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -77,23 +75,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToArgb32(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToArgb32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromBgr24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromBgr24(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -103,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -112,23 +109,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromBgr24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -138,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -147,23 +143,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToBgr24(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromBgra32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromBgra32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -173,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -182,23 +177,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromBgra32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -208,7 +202,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -217,23 +211,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToBgra32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromGray8(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromGray8(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Gray8 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -243,7 +236,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -252,23 +245,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray8(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromGray8(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -278,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -287,23 +279,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray8(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToGray8(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromGray16(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromGray16(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Gray16 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -313,7 +304,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -322,23 +313,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray16(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromGray16(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -348,7 +338,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -357,23 +347,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray16(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToGray16(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromRgb24(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgb24(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -383,7 +372,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -392,23 +381,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgb24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -418,7 +406,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -427,23 +415,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToRgb24(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromRgba32(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgba32(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -453,7 +440,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -462,23 +449,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgba32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -488,7 +474,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -497,23 +483,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToRgba32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromRgb48(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgb48(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -523,7 +508,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -532,23 +517,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgb48(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -558,7 +542,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -567,23 +551,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToRgb48(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void FromRgba64(ReadOnlySpan source, Span destPixels, int count) + internal virtual void FromRgba64(ReadOnlySpan source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -593,7 +576,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -602,23 +585,22 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void FromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); + this.FromRgba64(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels, int count) + internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); @@ -628,7 +610,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -637,7 +619,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourcePixels, MemoryMarshal.Cast(destBytes), count); + this.ToRgba64(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index 723b0358fe..484dde9ac0 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -16,19 +16,18 @@ #> /// - /// Converts 'count' elements in 'source` span of data to a span of -s. + /// Converts all pixels in 'source` span of into a span of -s. /// /// The source of data. /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) + internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels) { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < source.Length; i++) { ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); @@ -38,7 +37,7 @@ } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// /// The to the source bytes. @@ -47,7 +46,7 @@ [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void From<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.From<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); + this.From<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destPixels); } <# @@ -57,19 +56,18 @@ { #> /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// /// The span of source pixels /// The destination span of data. - /// The number of pixels to convert. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels, int count) + internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels) { - GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destPixels); - for (int i = 0; i < count; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); @@ -79,7 +77,7 @@ } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// /// The to the source pixels. @@ -88,7 +86,7 @@ [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourcePixels, MemoryMarshal.Cast>(destBytes), count); + this.To<#=pixelType#>(sourcePixels.Slice(count), MemoryMarshal.Cast>(destBytes)); } <# } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index e6ccaf914d..510645c4e9 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static PixelOperations Instance { get; } = default(TPixel).CreatePixelOperations(); /// - /// Bulk version of + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// /// The to the source vectors. /// The to the destination colors. @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Bulk version of . + /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// The to the source colors. /// The to the destination vectors. @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Bulk version of + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// /// The to the source vectors. /// The to the destination colors. @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Bulk version of . + /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// The to the source colors. /// The to the destination vectors. @@ -102,17 +102,19 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// Performs a bulk conversion of a collection of one pixel format into another. + /// Converts 'sourceColors.Length' pixels from 'sourceColors' into 'destinationColors'. /// - /// The pixel format. + /// The destination pixel type. /// The to the source colors. /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void To(ReadOnlySpan sourceColors, Span destinationColors, int count) + internal virtual void To( + ReadOnlySpan sourceColors, + Span destinationColors) where TDestinationPixel : struct, IPixel { - GuardSpans(sourceColors, nameof(sourceColors), destinationColors, nameof(destinationColors), count); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationColors, nameof(destinationColors)); + int count = sourceColors.Length; ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index dd947f337d..98a5d5eb51 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { Span row = source.GetPixelRowSpan(y); Span rgbaSpan = rgbaBuffer.GetSpan(); - PixelOperations.Instance.ToRgba32(row, rgbaSpan, source.Width); + PixelOperations.Instance.ToRgba32(row, rgbaSpan); ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan); // And loop through each column diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 72322f0d44..1cd8c0196b 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -59,13 +59,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().FromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().FromVector4(this.source.GetSpan(), this.destination.GetSpan()); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 2cbe549e4a..e313953a6c 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -65,13 +65,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan()); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 46b58f369d..051646f90b 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -35,15 +35,15 @@ namespace SixLabors.ImageSharp.Benchmarks Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToVector4(background, backgroundSpan); + PixelOperations.Instance.ToVector4(source, sourceSpan); for (int i = 0; i < destination.Length; i++) { destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } - PixelOperations.Instance.FromVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromVector4(destinationSpan, destination); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 8dca11caeb..886e02c139 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -34,8 +34,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer, width); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer, width); + PixelOperations.Instance.ToRgba64(aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 674603380f..9563edbb58 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -80,8 +80,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer, width); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer, width); + PixelOperations.Instance.ToRgba64(aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index 1543e2c8f4..03b77149be 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgra32(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgra32(workBuffer.GetSpan().Slice(0, w), row); } } } @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgr24(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgr24(workBuffer.GetSpan().Slice(w), row); } } } @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan(), row.Length); + PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan()); byte* destPtr = destPtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); From b69baf57f445b05d44b24727bbd1918ca3d9ed61 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 17:39:02 +0200 Subject: [PATCH 065/238] fix span length issues related to Vector4 conversion --- src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs | 12 ++++++------ .../Processors/Convolution/Convolution2DProcessor.cs | 4 ++-- .../Convolution/Convolution2PassProcessor.cs | 4 ++-- .../Processors/Convolution/ConvolutionProcessor.cs | 4 ++-- .../Quantization/FrameQuantizerBase{TPixel}.cs | 2 +- tests/ImageSharp.Tests/Issues/Issue412.cs | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 6c24ce05b2..6f0bba5cf9 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -93,12 +93,12 @@ namespace SixLabors.ImageSharp.PixelFormats Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background, backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan); + PixelOperations.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); + PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan, destination); + PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); } } @@ -127,12 +127,12 @@ namespace SixLabors.ImageSharp.PixelFormats Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background, backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan); + PixelOperations.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); + PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan, destination); + PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 90049a994d..a26fe6bfd1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -75,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index f38f16f1a9..98accb6061 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index d1b3f0ccf8..dcecf2b827 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -59,14 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index bc0ed0eab1..71999576be 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public virtual QuantizedFrame QuantizeFrame(ImageFrame image) { Guard.NotNull(image, nameof(image)); - + // Get the size of the source image int height = image.Height; int width = image.Width; diff --git a/tests/ImageSharp.Tests/Issues/Issue412.cs b/tests/ImageSharp.Tests/Issues/Issue412.cs index 6123c822b8..b0374ce1fa 100644 --- a/tests/ImageSharp.Tests/Issues/Issue412.cs +++ b/tests/ImageSharp.Tests/Issues/Issue412.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Issues [WithBlankImages(40, 30, PixelTypes.Rgba32)] public void AllPixelsExpectedToBeRedWhenAntialiasedDisabled(TestImageProvider provider) where TPixel : struct, IPixel { - using (var image = provider.GetImage()) + using (Image image = provider.GetImage()) { image.Mutate( context => From 30994e7640bfc0a4c0360e4dd97e5396669927d8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 22 Oct 2018 18:03:47 +0200 Subject: [PATCH 066/238] fix wrong Slice() usages --- .../PixelOperations{TPixel}.Generated.cs | 18 +++++++++--------- .../PixelOperations{TPixel}.Generated.tt | 2 +- .../Quantization/FrameQuantizerBase{TPixel}.cs | 2 +- .../ReferenceCodecs/SystemDrawingBridge.cs | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 1cbf487d76..07ecf87569 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToArgb32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToArgb32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToBgr24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -211,7 +211,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToBgra32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -279,7 +279,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray8(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToGray8(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -347,7 +347,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray16(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToGray16(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -415,7 +415,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToRgb24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -483,7 +483,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToRgba32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -551,7 +551,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToRgb48(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// @@ -619,7 +619,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourcePixels.Slice(count), MemoryMarshal.Cast(destBytes)); + this.ToRgba64(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index 484dde9ac0..ef73378a24 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -86,7 +86,7 @@ [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourcePixels.Slice(count), MemoryMarshal.Cast>(destBytes)); + this.To<#=pixelType#>(sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); } <# } diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index 71999576be..bc0ed0eab1 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public virtual QuantizedFrame QuantizeFrame(ImageFrame image) { Guard.NotNull(image, nameof(image)); - + // Get the size of the source image int height = image.Height; int width = image.Width; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index 03b77149be..e96825db1c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgr24(workBuffer.GetSpan().Slice(w), row); + PixelOperations.Instance.FromBgr24(workBuffer.GetSpan().Slice(0, w), row); } } } From cd543b24e78511e2d2b23d3a10a269cf0d43d663 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 22 Oct 2018 18:17:09 +0100 Subject: [PATCH 067/238] Bump build now Github should be returned to normal. --- .../TestUtilities/TestDataGenerator.cs | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 912b86e347..56cde41fc1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -1,10 +1,24 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; namespace SixLabors.ImageSharp.Tests { + /// + /// Helper methods that allow the creation of random test data. + /// internal static class TestDataGenerator { + /// + /// Creates an of the given length consisting of random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static float[] GenerateRandomFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; @@ -17,6 +31,14 @@ namespace SixLabors.ImageSharp.Tests return values; } + /// + /// Creates an of the given length consisting of random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static Vector4[] GenerateRandomVectorArray(this Random rnd, int length, float minVal, float maxVal) { var values = new Vector4[length]; @@ -33,20 +55,32 @@ namespace SixLabors.ImageSharp.Tests return values; } + /// + /// Creates an of the given length consisting of rounded random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; for (int i = 0; i < length; i++) { - values[i] = (float) Math.Round(rnd.GetRandomFloat(minVal, maxVal)); + values[i] = (float)Math.Round(rnd.GetRandomFloat(minVal, maxVal)); } return values; } - - + /// + /// Creates an of the given length consisting of random values. + /// + /// The pseudo-random number generator. + /// The length. + /// The . public static byte[] GenerateRandomByteArray(this Random rnd, int length) { byte[] values = new byte[length]; @@ -54,9 +88,6 @@ namespace SixLabors.ImageSharp.Tests return values; } - private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) - { - return (float)rnd.NextDouble() * (maxVal - minVal) + minVal; - } + private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) => ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; } } \ No newline at end of file From ca60ecf7f4564af0fafdbde62759a39d60a01a06 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 01:11:14 +0200 Subject: [PATCH 068/238] pass Configuration to Vector4 converters in PixelOperations --- .../Processing/BrushApplicator.cs | 2 +- .../Processing/ImageBrush{TPixel}.cs | 7 +- .../Processing/PatternBrush{TPixel}.cs | 7 +- .../Processors/Drawing/DrawImageProcessor.cs | 4 +- .../Processing/RecolorBrush{TPixel}.cs | 7 +- .../Processing/SolidBrush{TPixel}.cs | 10 ++- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 17 ++-- .../Decoder/JpegImagePostProcessor.cs | 12 ++- .../Formats/Jpeg/JpegDecoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 3 +- src/ImageSharp/ImageFrame{TPixel}.cs | 16 ++-- .../PixelFormats/PixelBlender{TPixel}.cs | 81 ++++++++++++++----- .../Rgba32.PixelOperations.cs | 20 +++-- .../RgbaVector.PixelOperations.cs | 9 ++- .../PixelFormats/PixelOperations{TPixel}.cs | 28 ++++++- .../Convolution/Convolution2DProcessor.cs | 4 +- .../Convolution/Convolution2PassProcessor.cs | 4 +- .../Convolution/ConvolutionProcessor.cs | 4 +- .../Dithering/PaletteDitherProcessorBase.cs | 19 ++++- .../Overlays/BackgroundColorProcessor.cs | 2 +- .../Processors/Overlays/GlowProcessor.cs | 2 +- .../Processors/Overlays/VignetteProcessor.cs | 2 +- .../FrameQuantizerBase{TPixel}.cs | 4 +- .../Processors/Quantization/IQuantizer.cs | 6 +- .../Quantization/OctreeQuantizer.cs | 5 +- .../PaletteFrameQuantizer{TPixel}.cs | 5 +- .../Quantization/PaletteQuantizer.cs | 15 ++-- .../Quantization/QuantizeProcessor.cs | 2 +- .../Processors/Quantization/WuQuantizer.cs | 5 +- .../Processors/Transforms/ResizeProcessor.cs | 4 +- .../Color/Bulk/FromVector4.cs | 10 ++- .../Color/Bulk/ToVector4.cs | 25 +++--- .../PixelBlenders/PorterDuffBulkVsPixel.cs | 8 +- .../Jpg/JpegImagePostProcessorTests.cs | 4 +- .../PorterDuffFunctionsTests_TPixel.cs | 20 ++--- .../PixelFormats/PixelOperationsTests.cs | 15 ++-- .../Quantization/QuantizedImageTests.cs | 25 ++++-- .../TestUtilities/TestImageExtensions.cs | 36 +++++---- 38 files changed, 301 insertions(+), 150 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs index 770d440656..0c6e0d3b40 100644 --- a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend(this.Target.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs index c3f81868be..1ef4bb9ec9 100644 --- a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs @@ -140,7 +140,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.source.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs index 2ce9a7ce57..46ed36f687 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs @@ -170,7 +170,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.Target.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index dc73420f30..0957904c62 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -79,8 +79,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing int width = maxX - minX; - MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; - var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); ParallelHelper.IterateRows( @@ -93,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing Span background = source.GetPixelRowSpan(y).Slice(minX, width); Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); - blender.Blend(memoryAllocator, background, background, foreground, this.Opacity); + blender.Blend(configuration, background, background, foreground, this.Opacity); } }); } diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs index 2968b68b55..09a1ff71fb 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs @@ -158,7 +158,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.Target.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs index 6b69c33f07..a77c6728b5 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs @@ -92,10 +92,11 @@ namespace SixLabors.ImageSharp.Processing Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; + Configuration configuration = this.Target.Configuration; if (this.Options.BlendPercentage == 1f) { - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); + this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); } else { @@ -108,7 +109,12 @@ namespace SixLabors.ImageSharp.Processing amountSpan[i] = scanline[i] * this.Options.BlendPercentage; } - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan); + this.Blender.Blend( + configuration, + destinationRow, + destinationRow, + this.Colors.GetSpan(), + amountSpan); } } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 7db347aa65..81adf52ddb 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; @@ -88,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.Gif // Quantize the image returning a palette. QuantizedFrame quantized = - this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); + this.quantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(image.Frames.RootFrame); // Get the number of bits. this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); @@ -151,7 +152,7 @@ namespace SixLabors.ImageSharp.Formats.Gif else { using (QuantizedFrame paletteQuantized - = palleteQuantizer.CreateFrameQuantizer(() => quantized.Palette).QuantizeFrame(frame)) + = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration(), () => quantized.Palette).QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } @@ -171,15 +172,17 @@ namespace SixLabors.ImageSharp.Formats.Gif if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. - if (previousFrame != null - && previousMeta.ColorTableLength != frameMetaData.ColorTableLength - && frameMetaData.ColorTableLength > 0) + if (previousFrame != null && previousMeta.ColorTableLength != frameMetaData.ColorTableLength + && frameMetaData.ColorTableLength > 0) { - quantized = this.quantizer.CreateFrameQuantizer(frameMetaData.ColorTableLength).QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer( + image.GetConfiguration(), + frameMetaData.ColorTableLength).QuantizeFrame(frame); } else { - quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) + .QuantizeFrame(frame); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 6bd287732d..1a6da2b2b0 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -26,6 +26,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// internal class JpegImagePostProcessor : IDisposable { + private readonly Configuration configuration; + /// /// The number of block rows to be processed in one Step. /// @@ -49,15 +51,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Initializes a new instance of the class. /// - /// The to use for buffer allocations. + /// The to configure internal operations. /// The representing the uncompressed spectral Jpeg data - public JpegImagePostProcessor(MemoryAllocator memoryAllocator, IRawJpegData rawJpeg) + public JpegImagePostProcessor(Configuration configuration, IRawJpegData rawJpeg) { + this.configuration = configuration; this.RawJpeg = rawJpeg; IJpegComponent c0 = rawJpeg.Components.First(); this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / BlockRowsPerStep; this.PostProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, PixelRowsPerStep); + MemoryAllocator memoryAllocator = configuration.MemoryAllocator; this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryAllocator, this, c)).ToArray(); this.rgbaBuffer = memoryAllocator.Allocate(rawJpeg.ImageSizeInPixels.Width); this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace); @@ -158,9 +162,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan()); Span destRow = destination.GetPixelRowSpan(yy); - + // TODO: Investigate if slicing is actually necessary - PixelOperations.Instance.FromVector4(this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); + PixelOperations.Instance.FromVector4(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 22d9cbdee4..36246c6820 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -936,7 +936,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private Image PostProcessIntoImage() where TPixel : struct, IPixel { - using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryAllocator, this)) + using (var postProcessor = new JpegImagePostProcessor(this.configuration, this)) { var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); postProcessor.PostProcess(image.Frames.RootFrame); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 84f7cb6cc4..71945d1302 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -237,7 +237,8 @@ namespace SixLabors.ImageSharp.Formats.Png } // Create quantized frame returning the palette and set the bit depth. - quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); + quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) + .QuantizeFrame(image.Frames.RootFrame); byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); bits = Math.Max(bits, quantizedBits); diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 25c517d442..bb95bb7b6d 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -21,7 +21,6 @@ namespace SixLabors.ImageSharp public sealed class ImageFrame : IPixelSource, IDisposable where TPixel : struct, IPixel { - private readonly Configuration configuration; private bool isDisposed; /// @@ -84,7 +83,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(width, height); this.MetaData = metaData ?? new ImageFrameMetaData(); @@ -118,7 +117,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.NotNull(metaData, nameof(metaData)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = new Buffer2D(memorySource, width, height); this.MetaData = metaData; @@ -134,7 +133,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); @@ -146,6 +145,11 @@ namespace SixLabors.ImageSharp /// public MemoryAllocator MemoryAllocator { get; } + /// + /// Gets the instance associated with this . + /// + internal Configuration Configuration { get; } + /// /// Gets the image pixels. Not private as Buffer2D requires an array in its constructor. /// @@ -254,7 +258,7 @@ namespace SixLabors.ImageSharp /// Clones the current instance. /// /// The - internal ImageFrame Clone() => this.Clone(this.configuration); + internal ImageFrame Clone() => this.Clone(this.Configuration); /// /// Clones the current instance. @@ -269,7 +273,7 @@ namespace SixLabors.ImageSharp /// The pixel format. /// The internal ImageFrame CloneAs() - where TPixel2 : struct, IPixel => this.CloneAs(this.configuration); + where TPixel2 : struct, IPixel => this.CloneAs(this.Configuration); /// /// Returns a copy of the image frame in the given pixel format. diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 6f0bba5cf9..5c8e506ae1 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -4,8 +4,8 @@ using System; using System.Buffers; using System.Numerics; + using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; namespace SixLabors.ImageSharp.PixelFormats { @@ -38,7 +38,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// A value between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount); + protected abstract void BlendFunction( + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + float amount); /// /// Blend 2 rows together. @@ -50,12 +54,16 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount); + protected abstract void BlendFunction( + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount); /// /// Blends 2 rows together /// - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -63,16 +71,21 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount) { - this.Blend(memoryManager, destination, background, source, amount); + this.Blend(configuration, destination, background, source, amount); } /// /// Blends 2 rows together /// /// the pixel format of the source span - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -80,25 +93,40 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount) where TPixelSrc : struct, IPixel { Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = + configuration.MemoryAllocator.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + background.Slice(0, background.Length), + backgroundSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + source.Slice(0, background.Length), + sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); + PixelOperations.Instance.FromScaledVector4( + configuration, + destinationSpan.Slice(0, background.Length), + destination); } } @@ -106,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Blends 2 rows together /// /// the pixel format of the source span - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -114,26 +142,41 @@ namespace SixLabors.ImageSharp.PixelFormats /// A value between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + float amount) where TPixelSrc : struct, IPixel { Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeBetweenOrEqualTo(amount, 0, 1, nameof(amount)); - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = + configuration.MemoryAllocator.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan); - PixelOperations.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + background.Slice(0, background.Length), + backgroundSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + source.Slice(0, background.Length), + sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination); + PixelOperations.Instance.FromScaledVector4( + configuration, + destinationSpan.Slice(0, background.Length), + destination); } } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index c25baa4512..0f5ddf3729 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -19,7 +19,10 @@ namespace SixLabors.ImageSharp.PixelFormats internal partial class PixelOperations : PixelOperations { /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal override void ToVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); @@ -31,7 +34,10 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) + internal override void FromVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) { Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); @@ -43,17 +49,21 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal override void ToScaledVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { - this.ToVector4(sourceColors, destinationVectors); + this.ToVector4(configuration, sourceColors, destinationVectors); } /// internal override void FromScaledVector4( + Configuration configuration, ReadOnlySpan sourceVectors, Span destinationColors) { - this.FromVector4(sourceVectors, destinationColors); + this.FromVector4(configuration, sourceVectors, destinationColors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index d1f3263659..cb12d944c7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// internal override void FromScaledVector4( + Configuration configuration, ReadOnlySpan sourceVectors, Span destinationColors) { @@ -29,12 +30,16 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToScaledVector4( + Configuration configuration, ReadOnlySpan sourceColors, Span destinationVectors) - => this.ToVector4(sourceColors, destinationVectors); + => this.ToVector4(configuration, sourceColors, destinationVectors); /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal override void ToVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 510645c4e9..8f3ea6c11a 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -24,10 +24,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// + /// A to configure internal operations /// The to the source vectors. /// The to the destination colors. - internal virtual void FromVector4(ReadOnlySpan sourceVectors, Span destinationColors) + internal virtual void FromVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); @@ -44,10 +49,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// + /// A to configure internal operations /// The to the source colors. /// The to the destination vectors. - internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal virtual void ToVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); @@ -64,10 +74,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// + /// A to configure internal operations /// The to the source vectors. /// The to the destination colors. - internal virtual void FromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors) + internal virtual void FromScaledVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); @@ -84,10 +99,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// + /// A to configure internal operations /// The to the source colors. /// The to the destination vectors. - internal virtual void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors) + internal virtual void ToScaledVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index a26fe6bfd1..bd1419e4bb 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -75,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 98accb6061..05007c3706 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index dcecf2b827..8ef64bdacc 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -59,14 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs index fd93801092..f01865ec05 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering { @@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// The vector representation of the image palette. /// - private readonly Vector4[] paletteVector; + private Vector4[] paletteVector; /// /// Initializes a new instance of the class. @@ -30,8 +31,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering protected PaletteDitherProcessorBase(TPixel[] palette) { this.Palette = palette ?? throw new ArgumentNullException(nameof(palette)); - this.paletteVector = new Vector4[this.Palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.Palette, this.paletteVector); } /// @@ -40,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public TPixel[] Palette { get; } /// - /// Returns the two closest colors from the palette calcluated via Euclidean distance in the Rgba space. + /// Returns the two closest colors from the palette calculated via Euclidean distance in the Rgba space. /// /// The source color to match. /// The . @@ -90,5 +89,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering return pair; } + + protected override void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + base.BeforeFrameApply(source, sourceRectangle, configuration); + + // Lazy init paletteVector: + if (this.paletteVector == null) + { + this.paletteVector = new Vector4[this.Palette.Length]; + PixelOperations.Instance.ToScaledVector4(configuration, this.Palette, this.paletteVector); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index 4adddd1536..25787ff922 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays // This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, colors.GetSpan(), destination, diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 93d6edff19..21f6be69f8 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); this.blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, destination, rowColors.GetSpan(), diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 52dade4eff..a8fa1d65c1 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); this.blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, destination, rowColors.GetSpan(), diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index bc0ed0eab1..a41127bfcb 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public abstract class FrameQuantizerBase : IFrameQuantizer where TPixel : struct, IPixel { + private readonly Configuration configuration; + /// /// A lookup table for colors /// @@ -79,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Collect the palette. Required before the second pass runs. TPixel[] palette = this.GetPalette(); this.paletteVector = new Vector4[palette.Length]; - PixelOperations.Instance.ToScaledVector4(palette, this.paletteVector); + PixelOperations.Instance.ToScaledVector4(image.Configuration, palette, this.paletteVector); var quantizedFrame = new QuantizedFrame(image.MemoryAllocator, width, height, palette); if (this.Dither) diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs index 3da09cde09..f1490a6d2b 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs @@ -19,18 +19,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Creates the generic frame quantizer /// + /// The to configure internal operations. /// The pixel format. /// The - IFrameQuantizer CreateFrameQuantizer() + IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel; /// /// Creates the generic frame quantizer /// /// The pixel format. + /// The to configure internal operations. /// The maximum number of colors to hold in the color palette. /// The - IFrameQuantizer CreateFrameQuantizer(int maxColors) + IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 22bb5223f0..38962c7680 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -74,13 +74,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public int MaxColors { get; } + /// /// - public IFrameQuantizer CreateFrameQuantizer() + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel => new OctreeFrameQuantizer(this); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { maxColors = maxColors.Clamp(1, DefaultMaxColors); diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index 625400413d..cab3af6de9 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -31,9 +31,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Initializes a new instance of the class. /// + /// The to configure internal operations. /// The palette quantizer. /// An array of all colors in the palette. - public PaletteFrameQuantizer(PaletteQuantizer quantizer, TPixel[] colors) + public PaletteFrameQuantizer(Configuration configuration, PaletteQuantizer quantizer, TPixel[] colors) : base(quantizer, true) { // TODO: Why is this value constrained? Gif has limitations but theoretically @@ -41,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors)); this.palette = colors; this.paletteVector = new Vector4[this.palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector); + PixelOperations.Instance.ToScaledVector4(configuration, this.palette, this.paletteVector); } /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 27ef05dfe9..361791253e 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -43,12 +43,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public IErrorDiffuser Diffuser { get; } /// - public virtual IFrameQuantizer CreateFrameQuantizer() + public virtual IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel - => this.CreateFrameQuantizer(() => NamedColors.WebSafePalette); + => this.CreateFrameQuantizer(configuration, () => NamedColors.WebSafePalette); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { TPixel[] websafe = NamedColors.WebSafePalette; @@ -56,21 +56,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (max != websafe.Length) { - return this.CreateFrameQuantizer(() => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); + return this.CreateFrameQuantizer(configuration, () => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); } - return this.CreateFrameQuantizer(() => websafe); + return this.CreateFrameQuantizer(configuration, () => websafe); } /// /// Gets the palette to use to quantize the image. /// /// The pixel format. + /// The to configure internal operations /// The method to return the palette. /// The - public IFrameQuantizer CreateFrameQuantizer(Func paletteFunction) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, Func paletteFunction) where TPixel : struct, IPixel - => new PaletteFrameQuantizer(this, paletteFunction.Invoke()); + => new PaletteFrameQuantizer(configuration, this, paletteFunction.Invoke()); private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs index bd5a6e9ec7..8da89bf94a 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(); + IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(configuration); using (QuantizedFrame quantized = executor.QuantizeFrame(source)) { int paletteCount = quantized.Palette.Length - 1; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 5123e737d3..4cd09a14f4 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -73,13 +73,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public int MaxColors { get; } + /// /// - public IFrameQuantizer CreateFrameQuantizer() + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel => new WuFrameQuantizer(this); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { maxColors = maxColors.Clamp(1, DefaultMaxColors); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 05c4464f18..4d4ed06ce1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span sourceRow = source.GetPixelRowSpan(y); Span tempRowSpan = tempRowBuffer.Span; - PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan); + PixelOperations.Instance.ToVector4(configuration, sourceRow, tempRowSpan); Vector4Utils.Premultiply(tempRowSpan); ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; @@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.FromVector4(tempRowSpan, targetRowSpan); + PixelOperations.Instance.FromVector4(configuration, tempRowSpan, targetRowSpan); } }); } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 1cd8c0196b..2b9573ed73 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -24,6 +24,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; + protected Configuration Configuration => Configuration.Default; + [Params( 64, 2048 @@ -33,8 +35,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [GlobalSetup] public void Setup() { - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); + this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] @@ -59,13 +61,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().FromVector4(this.source.GetSpan(), this.destination.GetSpan()); + new PixelOperations().FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan()); + PixelOperations.Instance.FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index e313953a6c..f0fee649af 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -10,10 +10,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Attributes.Jobs; -using BenchmarkDotNet.Configs; -using BenchmarkDotNet.Environments; -using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -27,20 +23,21 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected IMemoryOwner destination; + protected Configuration Configuration => Configuration.Default; + [Params( - 64, + 64, //256, //512, //1024, - 2048 - )] + 2048)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); + this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] @@ -65,13 +62,19 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void PixelOperations_Base() { - new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan()); + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); } [Benchmark] public void PixelOperations_Specialized() { - PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan()); + PixelOperations.Instance.ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 051646f90b..cdd56fa074 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Benchmarks public class PorterDuffBulkVsPixel : BenchmarkBase { + private Configuration Configuration => Configuration.Default; + private void BulkVectorConvert( Span destination, Span background, @@ -35,15 +37,15 @@ namespace SixLabors.ImageSharp.Benchmarks Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToVector4(background, backgroundSpan); - PixelOperations.Instance.ToVector4(source, sourceSpan); + PixelOperations.Instance.ToVector4(this.Configuration, background, backgroundSpan); + PixelOperations.Instance.ToVector4(this.Configuration, source, sourceSpan); for (int i = 0; i < destination.Length; i++) { destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } - PixelOperations.Instance.FromVector4(destinationSpan, destination); + PixelOperations.Instance.FromVector4(this.Configuration, destinationSpan, destination); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs index cfa421a82b..b3219115db 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { string imageFile = provider.SourceFileOrDescription; using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile)) - using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder)) + using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder)) using (var imageFrame = new ImageFrame(Configuration.Default, decoder.ImageWidth, decoder.ImageHeight)) { pp.DoPostProcessorStep(imageFrame); @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { string imageFile = provider.SourceFileOrDescription; using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile)) - using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder)) + using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder)) using (var image = new Image(decoder.ImageWidth, decoder.ImageHeight)) { pp.PostProcess(image.Frames.RootFrame); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs index 3ea9bcad40..7de1cbb190 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders { new TestPixel(1,1,1,1), new TestPixel(0,0,0,.8f), .5f, new TestPixel(0.6f, 0.6f, 0.6f, 1) }, }; - private MemoryAllocator MemoryAllocator { get; } = Configuration.Default.MemoryAllocator; + private Configuration Configuration => Configuration.Default; [Theory] [MemberData(nameof(NormalBlendFunctionData))] @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.NormalSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.NormalSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.MultiplySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.MultiplySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.AddSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.AddSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.SubtractSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.SubtractSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -206,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.ScreenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.ScreenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -245,7 +245,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.DarkenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.DarkenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.LightenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.LightenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.OverlaySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.OverlaySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -362,7 +362,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.HardLightSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.HardLightSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 0082e6c0ec..8314bd9b4d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -269,7 +269,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { this.Measure( times, - () => PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan())); + () => PixelOperations.Instance.ToVector4( + this.Configuration, + source.GetSpan(), + dest.GetSpan())); } } } @@ -333,6 +336,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 1111 }; + protected Configuration Configuration => Configuration.Default; + internal static PixelOperations Operations => PixelOperations.Instance; internal static TPixel[] CreateExpectedPixelData(Vector4[] source) @@ -367,7 +372,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromVector4(s, d.GetSpan()) + (s, d) => Operations.FromVector4(this.Configuration, s, d.GetSpan()) ); } @@ -381,7 +386,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromScaledVector4(s, d.GetSpan()) + (s, d) => Operations.FromScaledVector4(this.Configuration, s, d.GetSpan()) ); } @@ -417,7 +422,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToVector4(s, d.GetSpan()) + (s, d) => Operations.ToVector4(this.Configuration, s, d.GetSpan()) ); } @@ -431,7 +436,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan()) + (s, d) => Operations.ToScaledVector4(this.Configuration, s, d.GetSpan()) ); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 719e9793a0..fa855aef77 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -10,6 +10,8 @@ namespace SixLabors.ImageSharp.Tests { public class QuantizedImageTests { + private Configuration Configuration => Configuration.Default; + [Fact] public void QuantizersDitherByDefault() { @@ -21,15 +23,17 @@ namespace SixLabors.ImageSharp.Tests Assert.NotNull(octree.Diffuser); Assert.NotNull(wu.Diffuser); - Assert.True(palette.CreateFrameQuantizer().Dither); - Assert.True(octree.CreateFrameQuantizer().Dither); - Assert.True(wu.CreateFrameQuantizer().Dither); + Assert.True(palette.CreateFrameQuantizer(this.Configuration).Dither); + Assert.True(octree.CreateFrameQuantizer(this.Configuration).Dither); + Assert.True(wu.CreateFrameQuantizer(this.Configuration).Dither); } [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void PaletteQuantizerYieldsCorrectTransparentPixel(TestImageProvider provider, bool dither) + public void PaletteQuantizerYieldsCorrectTransparentPixel( + TestImageProvider provider, + bool dither) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -40,7 +44,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); @@ -51,7 +56,9 @@ namespace SixLabors.ImageSharp.Tests [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void OctreeQuantizerYieldsCorrectTransparentPixel(TestImageProvider provider, bool dither) + public void OctreeQuantizerYieldsCorrectTransparentPixel( + TestImageProvider provider, + bool dither) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -62,7 +69,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); @@ -84,7 +92,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index f055ce5480..29d39596b7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -30,27 +30,29 @@ namespace SixLabors.ImageSharp.Tests { MemoryAllocator memoryAllocator = ctx.MemoryAllocator; - ctx.Apply(img => - { - using (Buffer2D temp = memoryAllocator.Allocate2D(img.Width, img.Height)) - { - Span tempSpan = temp.GetSpan(); - foreach (ImageFrame frame in img.Frames) + ctx.Apply( + img => { - Span pixelSpan = frame.GetPixelSpan(); + Configuration configuration = img.GetConfiguration(); + using (Buffer2D temp = memoryAllocator.Allocate2D(img.Width, img.Height)) + { + Span tempSpan = temp.GetSpan(); + foreach (ImageFrame frame in img.Frames) + { + Span pixelSpan = frame.GetPixelSpan(); - PixelOperations.Instance.ToScaledVector4(pixelSpan, tempSpan); + PixelOperations.Instance.ToScaledVector4(configuration, pixelSpan, tempSpan); - for (int i = 0; i < tempSpan.Length; i++) - { - ref Vector4 v = ref tempSpan[i]; - v.W = 1F; - } + for (int i = 0; i < tempSpan.Length; i++) + { + ref Vector4 v = ref tempSpan[i]; + v.W = 1F; + } - PixelOperations.Instance.FromScaledVector4(tempSpan, pixelSpan); - } - } - }); + PixelOperations.Instance.FromScaledVector4(configuration, tempSpan, pixelSpan); + } + } + }); } public static Image DebugSave( From 53ac430e7e48ce2a4043ada85fac44a75a089567 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 01:49:24 +0200 Subject: [PATCH 069/238] Feed Configuration to all methods in PixelOperations --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 12 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 17 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 18 +- .../Encoder/YCbCrForwardConverter{TPixel}.cs | 6 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 + src/ImageSharp/Formats/Png/PngEncoderCore.cs | 46 +++-- .../Formats/Png/PngScanlineProcessor.cs | 8 +- src/ImageSharp/ImageFrame{TPixel}.cs | 4 +- .../PixelFormats/NamedColors{TPixel}.cs | 6 +- .../Argb32.PixelOperations.Generated.cs | 20 +- .../Bgr24.PixelOperations.Generated.cs | 20 +- .../Bgra32.PixelOperations.Generated.cs | 20 +- .../Gray16.PixelOperations.Generated.cs | 20 +- .../Gray8.PixelOperations.Generated.cs | 20 +- .../Rgb24.PixelOperations.Generated.cs | 20 +- .../Rgb48.PixelOperations.Generated.cs | 20 +- .../Rgba32.PixelOperations.Generated.cs | 20 +- .../Rgba64.PixelOperations.Generated.cs | 20 +- .../Generated/_Common.ttinclude | 6 +- .../PixelOperations{TPixel}.Generated.cs | 180 +++++++++++------- .../PixelOperations{TPixel}.Generated.tt | 20 +- .../PixelFormats/PixelOperations{TPixel}.cs | 2 + .../Quantization/WuFrameQuantizer{TPixel}.cs | 2 +- .../Color/Bulk/FromRgba32Bytes.cs | 11 +- .../ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs | 21 +- .../Color/Bulk/ToXyzw.cs | 21 +- .../PixelFormats/PixelOperationsTests.cs | 44 ++--- .../ImageComparison/ExactImageComparer.cs | 5 +- .../ImageComparison/TolerantImageComparer.cs | 5 +- .../ReferenceCodecs/MagickReferenceDecoder.cs | 12 +- .../ReferenceCodecs/SystemDrawingBridge.cs | 23 ++- 31 files changed, 405 insertions(+), 246 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 77cd322221..cea90cb45e 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -436,7 +436,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgr24Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgr24Bytes( + this.configuration, + row.GetSpan(), + pixelSpan, + width); } } } @@ -461,7 +465,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgra32Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgra32Bytes( + this.configuration, + row.GetSpan(), + pixelSpan, + width); } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 186ff812f7..a67c581eb0 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -3,6 +3,8 @@ using System; using System.IO; + +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; @@ -23,6 +25,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp private readonly MemoryAllocator memoryAllocator; + private Configuration configuration; + private BmpBitsPerPixel? bitsPerPixel; /// @@ -48,6 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); ImageMetaData metaData = image.MetaData; BmpMetaData bmpMetaData = metaData.GetFormatMetaData(BmpFormat.Instance); this.bitsPerPixel = this.bitsPerPixel ?? bmpMetaData.BitsPerPixel; @@ -163,7 +168,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = pixels.Height - 1; y >= 0; y--) { Span pixelSpan = pixels.GetRowSpan(y); - PixelOperations.Instance.ToBgra32Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length); + PixelOperations.Instance.ToBgra32Bytes( + this.configuration, + pixelSpan, + row.GetSpan(), + pixelSpan.Length); stream.Write(row.Array, 0, row.Length()); } } @@ -183,7 +192,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = pixels.Height - 1; y >= 0; y--) { Span pixelSpan = pixels.GetRowSpan(y); - PixelOperations.Instance.ToBgr24Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length); + PixelOperations.Instance.ToBgr24Bytes( + this.configuration, + pixelSpan, + row.GetSpan(), + pixelSpan.Length); stream.Write(row.Array, 0, row.Length()); } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 81adf52ddb..d7e2e40e29 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -27,6 +27,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// private readonly MemoryAllocator memoryAllocator; + /// + /// Configuration bound to the encoding operation. + /// + private Configuration configuration; + /// /// A reusable buffer used to reduce allocations. /// @@ -82,6 +87,8 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); + ImageMetaData metaData = image.MetaData; this.gifMetaData = metaData.GetFormatMetaData(GifFormat.Instance); this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; @@ -220,7 +227,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(quantized.Palette, rgbaSpan); + PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { @@ -322,7 +329,8 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The stream to write to. private void WriteComments(ImageMetaData metadata, Stream stream) { - if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) || string.IsNullOrEmpty(property.Value)) + if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) + || string.IsNullOrEmpty(property.Value)) { return; } @@ -420,7 +428,11 @@ namespace SixLabors.ImageSharp.Formats.Gif using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) { - PixelOperations.Instance.ToRgb24Bytes(image.Palette.AsSpan(), colorTable.GetSpan(), pixelCount); + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + image.Palette.AsSpan(), + colorTable.GetSpan(), + pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs index b2a8fccf4a..d775425c5c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs @@ -53,12 +53,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// /// Converts a 8x8 image area inside 'pixels' at position (x,y) placing the result members of the structure (, , ) /// - public void Convert(IPixelSource pixels, int x, int y) + public void Convert(ImageFrame frame, int x, int y) { - this.pixelBlock.LoadAndStretchEdges(pixels, x, y); + this.pixelBlock.LoadAndStretchEdges(frame, x, y); Span rgbSpan = this.rgbBlock.AsSpanUnsafe(); - PixelOperations.Instance.ToRgb24(this.pixelBlock.AsSpanUnsafe(), rgbSpan); + PixelOperations.Instance.ToRgb24(frame.Configuration, this.pixelBlock.AsSpanUnsafe(), rgbSpan); ref float yBlockStart = ref Unsafe.As(ref this.Y); ref float cbBlockStart = ref Unsafe.As(ref this.Cb); diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d66ac6c0d2..11c4d831b0 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -702,6 +702,7 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Rgb: PngScanlineProcessor.ProcessRgbScanline( + this.configuration, this.header, scanlineSpan, rowSpan, @@ -715,6 +716,7 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.RgbWithAlpha: PngScanlineProcessor.ProcessRgbaScanline( + this.configuration, this.header, scanlineSpan, rowSpan, diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 71945d1302..7ae716aa05 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -43,6 +43,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly MemoryAllocator memoryAllocator; + /// + /// The configuration instance for the decoding operation + /// + private Configuration configuration; + /// /// The maximum block size, defaults at 64k for uncompressed blocks. /// @@ -201,6 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Png Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); this.width = image.Width; this.height = image.Height; @@ -328,7 +334,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span luminanceSpan = luminanceBuffer.GetSpan(); ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan); - PixelOperations.Instance.ToGray16(rowSpan, luminanceSpan); + PixelOperations.Instance.ToGray16(this.configuration, rowSpan, luminanceSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) @@ -343,19 +349,28 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.bitDepth == 8) { // 8 bit grayscale - PixelOperations.Instance.ToGray8Bytes(rowSpan, rawScanlineSpan, rowSpan.Length); + PixelOperations.Instance.ToGray8Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + rowSpan.Length); } else { // 1, 2, and 4 bit grayscale - using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer(rowSpan.Length, AllocationOptions.Clean)) + using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer( + rowSpan.Length, + AllocationOptions.Clean)) { int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(this.bitDepth) - 1); Span tempSpan = temp.GetSpan(); - ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan); // We need to first create an array of luminance bytes then scale them down to the correct bit depth. - PixelOperations.Instance.ToGray8Bytes(rowSpan, tempSpan, rowSpan.Length); + PixelOperations.Instance.ToGray8Bytes( + this.configuration, + rowSpan, + tempSpan, + rowSpan.Length); this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor); } } @@ -371,7 +386,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); + PixelOperations.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4) @@ -391,7 +406,8 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); - Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); + Unsafe.Add(ref rawScanlineSpanRef, o) = + ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } } @@ -413,14 +429,22 @@ namespace SixLabors.ImageSharp.Formats.Png case 4: { // 8 bit Rgba - PixelOperations.Instance.ToRgba32Bytes(rowSpan, rawScanlineSpan, this.width); + PixelOperations.Instance.ToRgba32Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + this.width); break; } case 3: { // 8 bit Rgb - PixelOperations.Instance.ToRgb24Bytes(rowSpan, rawScanlineSpan, this.width); + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + this.width); break; } @@ -431,7 +455,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba64(rowSpan, rgbaSpan); + PixelOperations.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) @@ -454,7 +478,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Span rgbSpan = rgbBuffer.GetSpan(); ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan); - PixelOperations.Instance.ToRgb48(rowSpan, rgbSpan); + PixelOperations.Instance.ToRgb48(this.configuration, rowSpan, rgbSpan); // Can't map directly to byte array as it's big endian. for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index e4a2562e65..3fe590ee24 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Png { /// /// Provides methods to allow the decoding of raw scanlines to image rows of different pixel formats. + /// TODO: We should make this a stateful class or struct to reduce the number of arguments on methods (most are invariant). /// internal static class PngScanlineProcessor { @@ -346,6 +347,7 @@ namespace SixLabors.ImageSharp.Formats.Png } public static void ProcessRgbScanline( + Configuration configuration, in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, @@ -357,7 +359,6 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { TPixel pixel = default; - ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); if (!hasTrans) @@ -377,7 +378,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.FromRgb24Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgb24Bytes(configuration, scanlineSpan, rowSpan, header.Width); } return; @@ -500,6 +501,7 @@ namespace SixLabors.ImageSharp.Formats.Png } public static void ProcessRgbaScanline( + Configuration configuration, in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, @@ -526,7 +528,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - PixelOperations.Instance.FromRgba32Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgba32Bytes(configuration, scanlineSpan, rowSpan, header.Width); } } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index bb95bb7b6d..f69ae37574 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -252,7 +252,7 @@ namespace SixLabors.ImageSharp } /// - public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>({this.Width}x{this.Height})"; /// /// Clones the current instance. @@ -300,7 +300,7 @@ namespace SixLabors.ImageSharp { Span sourceRow = this.GetPixelRowSpan(y); Span targetRow = target.GetPixelRowSpan(y); - PixelOperations.Instance.To(sourceRow, targetRow); + PixelOperations.Instance.To(configuration, sourceRow, targetRow); } }); diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 1923faa1fc..08530c2bb5 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -739,7 +739,11 @@ namespace SixLabors.ImageSharp.PixelFormats var safe = new TPixel[constants.Length + 1]; Span constantsBytes = MemoryMarshal.Cast(constants.AsSpan()); - PixelOperations.Instance.FromRgba32Bytes(constantsBytes, safe, constants.Length); + PixelOperations.Instance.FromRgba32Bytes( + Configuration.Default, + constantsBytes, + safe, + constants.Length); return safe; } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 26e85e043d..09f10716e2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromArgb32(ReadOnlySpan source, Span destPixels) + internal override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 080a25429b..f8c61e4fac 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgr24(ReadOnlySpan source, Span destPixels) + internal override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 6a1bb6cdc3..9bddd18e9c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromBgra32(ReadOnlySpan source, Span destPixels) + internal override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index cbb9df4459..31c5755345 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray16(ReadOnlySpan source, Span destPixels) + internal override void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index b88f18e8de..14a2c858cf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromGray8(ReadOnlySpan source, Span destPixels) + internal override void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index 49c56f4fa2..f8b80020ec 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb24(ReadOnlySpan source, Span destPixels) + internal override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index cda6dbf72c..5741b10706 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgb48(ReadOnlySpan source, Span destPixels) + internal override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index ab264f8701..9f7b624c07 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba32(ReadOnlySpan source, Span destPixels) + internal override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index 4bc6b101ae..411178b825 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.PixelFormats { /// - internal override void FromRgba64(ReadOnlySpan source, Span destPixels) + internal override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - internal override void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index 176075a40f..bc23edb015 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -19,7 +19,7 @@ using System.Runtime.InteropServices; #> /// - internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) + internal override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -27,7 +27,7 @@ using System.Runtime.InteropServices; } /// - internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) + internal override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -42,7 +42,7 @@ using System.Runtime.InteropServices; #> /// - internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) + internal override void To<#=toPixelType#>(Configuration configuration, ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 07ecf87569..207a8767d6 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -13,9 +13,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromArgb32(ReadOnlySpan source, Span destPixels) + internal virtual void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -32,24 +33,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromArgb32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromArgb32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromArgb32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -66,24 +69,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToArgb32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToArgb32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToArgb32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToArgb32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromBgr24(ReadOnlySpan source, Span destPixels) + internal virtual void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -100,24 +105,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgr24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgr24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromBgr24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -134,24 +141,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgr24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToBgr24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgr24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgr24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromBgra32(ReadOnlySpan source, Span destPixels) + internal virtual void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -168,24 +177,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromBgra32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromBgra32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromBgra32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -202,24 +213,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgra32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToBgra32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToBgra32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgra32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromGray8(ReadOnlySpan source, Span destPixels) + internal virtual void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -236,24 +249,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromGray8Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray8Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray8(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromGray8(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToGray8(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -270,24 +285,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray8Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToGray8Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray8(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToGray8(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromGray16(ReadOnlySpan source, Span destPixels) + internal virtual void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -304,24 +321,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromGray16Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromGray16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromGray16(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromGray16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToGray16(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -338,24 +357,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToGray16Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToGray16Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToGray16(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToGray16(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgb24(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -372,24 +393,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb24(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgb24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -406,24 +429,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb24Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgb24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb24(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgba32(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -440,24 +465,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba32(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgba32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -474,24 +501,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba32Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgba32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba32(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgb48(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -508,24 +537,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgb48Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgb48(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgb48(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -542,24 +573,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb48Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgb48Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgb48(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb48(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void FromRgba64(ReadOnlySpan source, Span destPixels) + internal virtual void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -576,24 +609,26 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void FromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void FromRgba64Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.FromRgba64(MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + this.FromRgba64(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); } /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span destPixels) + internal virtual void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -610,16 +645,17 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba64Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void ToRgba64Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.ToRgba64(sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba64(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index ef73378a24..8579423b34 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -18,9 +18,10 @@ /// /// Converts all pixels in 'source` span of into a span of -s. /// + /// A to configure internal operations /// The source of data. /// The to the destination pixels. - internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels) + internal virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span destPixels) { Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); @@ -37,16 +38,17 @@ } /// - /// A helper for that expects a byte span. + /// A helper for that expects a byte span. /// The layout of the data in 'sourceBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source bytes. /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void From<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + internal void From<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) { - this.From<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destPixels); + this.From<#=pixelType#>(configuration, MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destPixels); } <# @@ -58,9 +60,10 @@ /// /// Converts all pixels of the 'sourcePixels` span to a span of -s. /// + /// A to configure internal operations /// The span of source pixels /// The destination span of data. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels) + internal virtual void To<#=pixelType#>(Configuration configuration, ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels) { Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); @@ -77,16 +80,17 @@ } /// - /// A helper for that expects a byte span as destination. + /// A helper for that expects a byte span as destination. /// The layout of the data in 'destBytes' must be compatible with layout. /// + /// A to configure internal operations /// The to the source pixels. /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void To<#=pixelType#>Bytes(ReadOnlySpan sourcePixels, Span destBytes, int count) + internal void To<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) { - this.To<#=pixelType#>(sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); + this.To<#=pixelType#>(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); } <# } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 8f3ea6c11a..ea03af683d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -125,9 +125,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// Converts 'sourceColors.Length' pixels from 'sourceColors' into 'destinationColors'. /// /// The destination pixel type. + /// A to configure internal operations /// The to the source colors. /// The to the destination colors. internal virtual void To( + Configuration configuration, ReadOnlySpan sourceColors, Span destinationColors) where TDestinationPixel : struct, IPixel diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 98a5d5eb51..43d22597df 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { Span row = source.GetPixelRowSpan(y); Span rgbaSpan = rgbaBuffer.GetSpan(); - PixelOperations.Instance.ToRgba32(row, rgbaSpan); + PixelOperations.Instance.ToRgba32(source.Configuration, row, rgbaSpan); ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan); // And loop through each column diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs index f3245ebaf5..32565c23dc 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs @@ -20,14 +20,17 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private IMemoryOwner source; + private Configuration configuration; + [Params(16, 128, 1024)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count * 4); + this.configuration = Configuration.Default; + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count); + this.source = this.configuration.MemoryAllocator.Allocate(this.Count * 4); } [GlobalCleanup] @@ -55,13 +58,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Benchmark] public void CommonBulk() { - new PixelOperations().FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); } [Benchmark] public void OptimizedBulk() { - PixelOperations.Instance.FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs index f96023f000..912c3e4b2e 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs @@ -17,14 +17,17 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private IMemoryOwner destination; + private Configuration configuration; + [Params(16, 128, 1024)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count * 3); + this.configuration = Configuration.Default; + this.source = this.configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count * 3); } [GlobalCleanup] @@ -35,10 +38,20 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark(Baseline = true)] - public void CommonBulk() => new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + public void CommonBulk() => + new PixelOperations().ToRgb24Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); [Benchmark] - public void OptimizedBulk() => PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + public void OptimizedBulk() => + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); } public class ToXyz_Rgba32 : ToXyz diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs index 0cf7087d4c..37694f64cd 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -19,14 +19,17 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private IMemoryOwner destination; + private Configuration configuration; + [Params(16, 128, 1024)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count * 4); + this.configuration = Configuration.Default; + this.source = this.configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count * 4); } [GlobalCleanup] @@ -56,10 +59,20 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } [Benchmark] - public void CommonBulk() => new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + public void CommonBulk() => + new PixelOperations().ToRgba32Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); [Benchmark] - public void OptimizedBulk() => PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + public void OptimizedBulk() => + PixelOperations.Instance.ToRgba32Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); } public class ToXyzw_Rgba32 : ToXyzw diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs index 8314bd9b4d..e66ca9a714 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) ); } } @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -198,7 +198,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -243,7 +243,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) ); } } @@ -457,7 +457,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromArgb32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -483,7 +483,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToArgb32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -504,7 +504,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgr24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -528,7 +528,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgr24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -549,7 +549,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgra32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -574,7 +574,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgra32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -595,7 +595,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -619,7 +619,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb24Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -640,7 +640,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -665,7 +665,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba32Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -686,7 +686,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb48Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -714,7 +714,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb48Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -735,7 +735,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.FromRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba64Bytes(this.Configuration, s, d.GetSpan(), count) ); } @@ -765,7 +765,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba64Bytes(this.Configuration, s, d.GetSpan(), count) ); } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 886e02c139..462782ba5e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -28,14 +28,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison var bBuffer = new Rgba64[width]; var differences = new List(); + Configuration configuration = expected.Configuration; for (int y = 0; y < actual.Height; y++) { Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer); + PixelOperations.Instance.ToRgba64(configuration, aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(configuration, bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 9563edbb58..be12f56211 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -74,14 +74,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison float totalDifference = 0F; var differences = new List(); + Configuration configuration = expected.Configuration; for (int y = 0; y < actual.Height; y++) { Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer); + PixelOperations.Instance.ToRgba64(configuration, aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(configuration, bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 2409ff9add..3dd330e4d3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -31,14 +31,22 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); - PixelOperations.Instance.FromRgba32Bytes(data, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba32Bytes( + configuration, + data, + resultPixels, + resultPixels.Length); } else if (magickImage.Depth == 16) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); - PixelOperations.Instance.FromRgba64Bytes(bytes, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba64Bytes( + configuration, + bytes, + resultPixels, + resultPixels.Length); } else { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index e96825db1c..7e87c23db5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -33,7 +33,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs if (bmp.PixelFormat != PixelFormat.Format32bppArgb) { - throw new ArgumentException($"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", nameof(bmp)); + throw new ArgumentException( + $"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", + nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); @@ -43,6 +45,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = w * sizeof(Bgra32); var image = new Image(w, h); + Configuration configuration = image.GetConfiguration(); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { @@ -55,7 +58,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgra32(workBuffer.GetSpan().Slice(0, w), row); + PixelOperations.Instance.FromBgra32( + configuration, + workBuffer.GetSpan().Slice(0, w), + row); } } } @@ -79,7 +85,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs if (bmp.PixelFormat != PixelFormat.Format24bppRgb) { - throw new ArgumentException($"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", nameof(bmp)); + throw new ArgumentException( + $"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", + nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); @@ -89,6 +97,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = w * sizeof(Bgr24); var image = new Image(w, h); + Configuration configuration = image.GetConfiguration(); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { @@ -101,7 +110,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.FromBgr24(workBuffer.GetSpan().Slice(0, w), row); + PixelOperations.Instance.FromBgr24( + configuration, + workBuffer.GetSpan().Slice(0, w), + row); } } } @@ -112,6 +124,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs internal static unsafe Bitmap To32bppArgbSystemDrawingBitmap(Image image) where TPixel : struct, IPixel { + Configuration configuration = image.GetConfiguration(); int w = image.Width; int h = image.Height; @@ -130,7 +143,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan()); + PixelOperations.Instance.ToBgra32(configuration, row, workBuffer.GetSpan()); byte* destPtr = destPtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); From e408b5ca91e22e40c8a88b3aaf0a0e98c79ea067 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 11:32:22 +0200 Subject: [PATCH 070/238] revert addition of unnecessary `[DebuggerStepThrough]` --- src/ImageSharp/Common/Helpers/Guard.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index cd53e3d69a..d8cf69a52e 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -21,7 +21,6 @@ namespace SixLabors.ImageSharp /// The name of the parameter that is to be checked. /// is null [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void NotNull(T value, string parameterName) where T : class { @@ -39,7 +38,6 @@ namespace SixLabors.ImageSharp /// is null. /// is empty or contains only blanks. [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void NotNullOrWhiteSpace(string value, string parameterName) { if (value is null) @@ -62,7 +60,6 @@ namespace SixLabors.ImageSharp /// is null. /// is empty. [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void NotNullOrEmpty(ICollection value, string parameterName) { if (value is null) @@ -87,7 +84,6 @@ namespace SixLabors.ImageSharp /// is greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeLessThan(TValue value, TValue max, string parameterName) where TValue : IComparable { @@ -109,7 +105,6 @@ namespace SixLabors.ImageSharp /// is greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName) where TValue : IComparable { @@ -131,7 +126,6 @@ namespace SixLabors.ImageSharp /// is less than the minimum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeGreaterThan(TValue value, TValue min, string parameterName) where TValue : IComparable { @@ -155,7 +149,6 @@ namespace SixLabors.ImageSharp /// is less than the minimum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName) where TValue : IComparable { @@ -178,7 +171,6 @@ namespace SixLabors.ImageSharp /// is less than the minimum value of greater than the maximum value. /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName) where TValue : IComparable { @@ -199,7 +191,6 @@ namespace SixLabors.ImageSharp /// is false /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void IsTrue(bool target, string parameterName, string message) { if (!target) @@ -219,7 +210,6 @@ namespace SixLabors.ImageSharp /// is true /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void IsFalse(bool target, string parameterName, string message) { if (target) @@ -239,7 +229,6 @@ namespace SixLabors.ImageSharp /// has less than items /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName) { if (source.Length < minLength) @@ -257,7 +246,6 @@ namespace SixLabors.ImageSharp /// The destination span /// The name of the argument for 'destination' [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void DestinationShouldNotBeTooShort( ReadOnlySpan source, Span destination, @@ -280,7 +268,6 @@ namespace SixLabors.ImageSharp /// has less than items /// [MethodImpl(InliningOptions.ShortMethod)] - [DebuggerStepThrough] public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName) { if (source.Length < minLength) From 8dce0c740ce9660bd41b039a5023bbe204cdbf05 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 11:06:32 +0200 Subject: [PATCH 071/238] bitwise conversion + benchmarks WIP --- .../Decoder/JpegImagePostProcessor.cs | 2 +- src/ImageSharp/PixelFormats/PixelConverter.cs | 47 ++++++ .../FrameQuantizerBase{TPixel}.cs | 2 - .../PixelConversion_ConvertFromRgba32.cs | 144 +++++++++++++---- .../General/PixelConversion/TestArgb.cs | 62 ++++---- .../General/PixelConversion/TestRgba.cs | 14 +- .../PixelFormats/PixelConverterTests.cs | 150 ++++++++++++++++++ .../PixelFormats/Rgba32Tests.cs | 1 + 8 files changed, 347 insertions(+), 75 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelConverter.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 1a6da2b2b0..7ce86b4c9b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan()); Span destRow = destination.GetPixelRowSpan(yy); - + // TODO: Investigate if slicing is actually necessary PixelOperations.Instance.FromVector4(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); } diff --git a/src/ImageSharp/PixelFormats/PixelConverter.cs b/src/ImageSharp/PixelFormats/PixelConverter.cs new file mode 100644 index 0000000000..3686092cd2 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelConverter.cs @@ -0,0 +1,47 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Contains optimized implementations for conversion between pixel formats. + /// + /// + /// Implementations are based on ideas in: + /// https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs#L84 + /// The JIT should be able to detect and optimize ROL and ROR patterns. + /// + internal static class PixelConverter + { + public static class Rgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba): + return (packedRgba << 8) | (packedRgba >> 24); + } + } + + public static class Argb32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToRgba32(uint packedArgb) + { + // packedArgb = [bb gg rr aa] + // ROR(8, packedArgb): + return (packedArgb >> 8) | (packedArgb << 24); + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index a41127bfcb..a8c6c5d7e0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -17,8 +17,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public abstract class FrameQuantizerBase : IFrameQuantizer where TPixel : struct, IPixel { - private readonly Configuration configuration; - /// /// A lookup table for colors /// diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 6a96c8576e..1be8347c3d 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -1,6 +1,8 @@ // ReSharper disable InconsistentNaming +using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; @@ -8,14 +10,14 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { - public class PixelConversion_ConvertFromRgba32 + public abstract class PixelConversion_ConvertFromRgba32 { - struct ConversionRunner + internal struct ConversionRunner where T : struct, ITestPixel { - private T[] dest; + public readonly T[] dest; - private Rgba32[] source; + public readonly Rgba32[] source; public ConversionRunner(int count) { @@ -67,72 +69,146 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } } - private ConversionRunner compatibleMemLayoutRunner; + internal ConversionRunner compatibleMemLayoutRunner; - private ConversionRunner permutedRunner; + internal ConversionRunner permutedRunnerRgbaToArgb; - [Params(32)] + [Params( + 256, + 2048 + )] public int Count { get; set; } [GlobalSetup] public void Setup() { this.compatibleMemLayoutRunner = new ConversionRunner(this.Count); - this.permutedRunner = new ConversionRunner(this.Count); + this.permutedRunnerRgbaToArgb = new ConversionRunner(this.Count); } + } + public class PixelConversion_ConvertFromRgba32_Compatible : PixelConversion_ConvertFromRgba32 + { [Benchmark(Baseline = true)] - public void CompatibleByRef() + public void ByRef() { this.compatibleMemLayoutRunner.RunByRefConversion(); } [Benchmark] - public void CompatibleByVal() + public void ByVal() { this.compatibleMemLayoutRunner.RunByValConversion(); } [Benchmark] - public void CompatibleFromBytes() + public void FromBytes() { this.compatibleMemLayoutRunner.RunFromBytesConversion(); } + [Benchmark] + public void Inline() + { + ref Rgba32 sBase = ref this.compatibleMemLayoutRunner.source[0]; + ref Rgba32 dBase = ref Unsafe.As(ref this.compatibleMemLayoutRunner.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i); + } + } + + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------- |------ |---------:|---------:|---------:|-------:|---------:| + // ByRef | 256 | 128.5 ns | 1.217 ns | 1.138 ns | 1.00 | 0.00 | + // ByVal | 256 | 196.7 ns | 2.792 ns | 2.612 ns | 1.53 | 0.02 | + // FromBytes | 256 | 321.7 ns | 2.180 ns | 1.820 ns | 2.50 | 0.03 | + // Inline | 256 | 129.9 ns | 2.759 ns | 2.581 ns | 1.01 | 0.02 | + } + + public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConversion_ConvertFromRgba32 + { + [Benchmark(Baseline = true)] + public void ByRef() + { + this.permutedRunnerRgbaToArgb.RunByRefConversion(); + } + + [Benchmark] + public void ByVal() + { + this.permutedRunnerRgbaToArgb.RunByValConversion(); + } + + [Benchmark] + public void FromBytes() + { + this.permutedRunnerRgbaToArgb.RunFromBytesConversion(); + } [Benchmark] - public void PermutedByRef() + public void InlineShuffle() { - this.permutedRunner.RunByRefConversion(); + ref Rgba32 sBase = ref this.permutedRunnerRgbaToArgb.source[0]; + ref TestArgb dBase = ref this.permutedRunnerRgbaToArgb.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + ref TestArgb d = ref Unsafe.Add(ref dBase, i); + + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + } } [Benchmark] - public void PermutedByVal() + public void PixelConverter_Rgba32_ToArgb32() { - this.permutedRunner.RunByValConversion(); + ref uint sBase = ref Unsafe.As(ref this.permutedRunnerRgbaToArgb.source[0]); + ref uint dBase = ref Unsafe.As(ref this.permutedRunnerRgbaToArgb.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + } } [Benchmark] - public void PermutedFromBytes() + public void PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer() { - this.permutedRunner.RunFromBytesConversion(); + Span source = MemoryMarshal.Cast(this.permutedRunnerRgbaToArgb.source); + Span dest = MemoryMarshal.Cast(this.permutedRunnerRgbaToArgb.dest); + source.CopyTo(dest); + + ref uint dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref dBase, i); + Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + } } - } - /* - * Results: - * Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | - * ------------------ |------ |----------- |---------- |------- |-------------- | - * CompatibleByRef | 32 | 20.6339 ns | 0.0742 ns | 1.00 | 0.00 | - * CompatibleByVal | 32 | 23.7425 ns | 0.0997 ns | 1.15 | 0.01 | - * CompatibleFromBytes | 32 | 38.7017 ns | 0.1103 ns | 1.88 | 0.01 | - * PermutedByRef | 32 | 39.2892 ns | 0.1366 ns | 1.90 | 0.01 | - * PermutedByVal | 32 | 38.5178 ns | 0.1946 ns | 1.87 | 0.01 | - * PermutedFromBytes | 32 | 38.6683 ns | 0.0801 ns | 1.87 | 0.01 | - * - * !!! Conclusion !!! - * All memory-incompatible (permuted) variants are equivalent with the the "FromBytes" solution. - * In memory compatible cases we should use the optimized Bulk-copying variant anyways, - * so there is no benefit introducing non-bulk API-s other than FromBytes() OR FromRgba32(). - */ + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------------------------------------------------------- |------ |-----------:|-----------:|-----------:|-------:|---------:| + // ByRef | 256 | 328.7 ns | 6.6141 ns | 6.1868 ns | 1.00 | 0.00 | + // ByVal | 256 | 322.0 ns | 4.3541 ns | 4.0728 ns | 0.98 | 0.02 | + // FromBytes | 256 | 321.5 ns | 3.3499 ns | 3.1335 ns | 0.98 | 0.02 | + // InlineShuffle | 256 | 330.7 ns | 4.2525 ns | 3.9778 ns | 1.01 | 0.02 | + // PixelConverter_Rgba32_ToArgb32 | 256 | 167.4 ns | 0.6357 ns | 0.5309 ns | 0.51 | 0.01 | + // PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 256 | 196.6 ns | 0.8929 ns | 0.7915 ns | 0.60 | 0.01 | + // | | | | | | | + // ByRef | 2048 | 2,534.4 ns | 8.2947 ns | 6.9265 ns | 1.00 | 0.00 | + // ByVal | 2048 | 2,638.5 ns | 52.6843 ns | 70.3320 ns | 1.04 | 0.03 | + // FromBytes | 2048 | 2,517.2 ns | 40.8055 ns | 38.1695 ns | 0.99 | 0.01 | + // InlineShuffle | 2048 | 2,546.5 ns | 21.2506 ns | 19.8778 ns | 1.00 | 0.01 | + // PixelConverter_Rgba32_ToArgb32 | 2048 | 1,265.7 ns | 5.1397 ns | 4.5562 ns | 0.50 | 0.00 | + // PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 2048 | 1,410.3 ns | 11.1939 ns | 9.9231 ns | 0.56 | 0.00 |// + } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs index 61a7df81d6..76de794eca 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -9,81 +9,81 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [StructLayout(LayoutKind.Sequential)] struct TestArgb : ITestPixel { - private byte a, r, g, b; + public byte A, R, G, B; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromRgba32(Rgba32 p) { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; + this.R = p.R; + this.G = p.G; + this.B = p.B; + this.A = p.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromRgba32(ref Rgba32 p) { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; + this.R = p.R; + this.G = p.G; + this.B = p.B; + this.A = p.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte r, byte g, byte b, byte a) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; + this.R = r; + this.G = g; + this.B = b; + this.A = a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.R = (byte)p.X; + this.G = (byte)p.Y; + this.B = (byte)p.Z; + this.A = (byte)p.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(ref Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.R = (byte)p.X; + this.G = (byte)p.Y; + this.B = (byte)p.Z; + this.A = (byte)p.W; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32 ToRgba32() { - return new Rgba32(this.r, this.g, this.b, this.a); + return new Rgba32(this.R, this.G, this.B, this.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToRgba32(ref Rgba32 dest) { - dest.R = this.r; - dest.G = this.g; - dest.B = this.b; - dest.A = this.a; + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4(this.r, this.g, this.b, this.a); + return new Vector4(this.R, this.G, this.B, this.A); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToVector4(ref Vector4 dest) { - dest.X = this.r; - dest.Y = this.g; - dest.Z = this.b; - dest.W = this.a; + dest.X = this.R; + dest.Y = this.G; + dest.Z = this.B; + dest.W = this.A; } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index cc8cf352a8..36d5f3e5b9 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [StructLayout(LayoutKind.Sequential)] struct TestRgba : ITestPixel { - private byte r, g, b, a; + public byte R, G, B, A; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromRgba32(Rgba32 source) @@ -26,10 +26,10 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte r, byte g, byte b, byte a) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; + this.R = r; + this.G = g; + this.B = b; + this.A = a; } public void FromVector4(Vector4 source) @@ -57,13 +57,13 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() { - return new Vector4(this.r, this.g, this.b, this.a) * new Vector4(1f / 255f); + return new Vector4(this.R, this.G, this.B, this.A) * new Vector4(1f / 255f); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyToVector4(ref Vector4 dest) { - var tmp = new Vector4(this.r, this.g, this.b, this.a); + var tmp = new Vector4(this.R, this.G, this.B, this.A); tmp *= new Vector4(1f / 255f); dest = tmp; } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs new file mode 100644 index 0000000000..83c4e34f2f --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -0,0 +1,150 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class PixelConverterTests + { + public static readonly TheoryData RgbaData = + new TheoryData + { + { 0, 0, 0, 0 }, + { 0, 0, 0, 255 }, + { 0, 0, 255, 0 }, + { 0, 255, 0, 0 }, + { 255, 0, 0, 0 }, + { 255, 255, 255, 255 }, + { 0, 0, 0, 1 }, + { 0, 0, 1, 0 }, + { 0, 1, 0, 0 }, + { 1, 0, 0, 0 }, + { 3, 5, 7, 11 }, + { 67, 71, 101, 109 } + }; + + [Theory] + [MemberData(nameof(RgbaData))] + public void Rgba32ToArgb32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.Rgba32.ToArgb32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.ToArgb32(s).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void Argb32ToRgba32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.Argb32.ToRgba32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.ToRgba32(s).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + + private static class ReferenceImplementations + { + public static Rgba32 MakeRgba32(byte r, byte g, byte b, byte a) + { + Rgba32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Argb32 MakeArgb32(byte r, byte g, byte b, byte a) + { + Argb32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Bgra32 MakeBgra32(byte r, byte g, byte b, byte a) + { + Bgra32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Argb32 ToArgb32(Rgba32 s) + { + Argb32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Argb32 ToArgb32(Bgra32 s) + { + Argb32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Rgba32 ToRgba32(Argb32 s) + { + Rgba32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Rgba32 ToRgba32(Bgra32 s) + { + Rgba32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Bgra32 ToBgra32(Rgba32 s) + { + Bgra32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + + public static Bgra32 ToBgra32(Argb32 s) + { + Bgra32 d = default; + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + return d; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 8c702f66da..ad1d137406 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -5,6 +5,7 @@ using System; using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using Xunit; +using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.PixelFormats { From 15415ef3c4bb6f34856eba961fd28c438ba58db5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 19:03:03 +0200 Subject: [PATCH 072/238] Update xmldoc --- src/ImageSharp/PixelFormats/IPixel.cs | 36 +++++++++---------- .../PixelFormats/PixelOperations{TPixel}.cs | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 13e35cce05..1277406869 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -24,93 +24,93 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// An interface that represents a pixel type. + /// A base interface for all pixels, defining the mandatory operations to be implemented by a pixel type. /// public interface IPixel { /// - /// Sets the packed representation from a scaled . + /// Initializes the pixel instance from a generic ("scaled") . /// - /// The vector to create the packed representation from. + /// The vector to load the pixel from. void FromScaledVector4(Vector4 vector); /// - /// Expands the packed representation into a scaled - /// with values clamped between 0 and 1. + /// Expands the pixel into a generic ("scaled") representation + /// with values scaled and clamped between 0 and 1. /// The vector components are typically expanded in least to greatest significance order. /// /// The . Vector4 ToScaledVector4(); /// - /// Sets the packed representation from a . + /// Initializes the pixel instance from a which is specific to the current pixel type. /// - /// The vector to create the packed representation from. + /// The vector to load the pixel from. void FromVector4(Vector4 vector); /// - /// Expands the packed representation into a . + /// Expands the pixel into a which is specific to the current pixel type. /// The vector components are typically expanded in least to greatest significance order. /// /// The . Vector4 ToVector4(); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromArgb32(Argb32 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromBgr24(Bgr24 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromBgra32(Bgra32 source); /// - /// Packs the Pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromGray8(Gray8 source); /// - /// Packs the Pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromGray16(Gray16 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromRgb24(Rgb24 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromRgba32(Rgba32 source); /// - /// Expands the packed representation into an . + /// Convert the pixel instance into representation. /// /// The reference to the destination pixel void ToRgba32(ref Rgba32 dest); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromRgb48(Rgb48 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. void FromRgba64(Rgba64 source); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 510645c4e9..126db85335 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats return; } - // Normal converson + // Normal conversion ref TDestinationPixel destRef = ref MemoryMarshal.GetReference(destinationColors); for (int i = 0; i < count; i++) { From 96d0ae80b9b743ca8e67435e40ba7ff9c0937b75 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 20:14:05 +0200 Subject: [PATCH 073/238] Rgba32 <-> Argb32 <-> Bgra32 --- src/ImageSharp/PixelFormats/PixelConverter.cs | 76 +++++++- .../PixelFormats/PixelOperations{TPixel}.cs | 22 --- .../PixelConversion_ConvertFromRgba32.cs | 4 +- .../PixelFormats/PixelConverterTests.cs | 167 +++++++++--------- 4 files changed, 158 insertions(+), 111 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelConverter.cs b/src/ImageSharp/PixelFormats/PixelConverter.cs index 3686092cd2..8fde490fda 100644 --- a/src/ImageSharp/PixelFormats/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/PixelConverter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats @@ -16,32 +17,91 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal static class PixelConverter { - public static class Rgba32 + public static class FromRgba32 { /// - /// Converts a packed to . + /// Converts a packed to . /// [MethodImpl(InliningOptions.ShortMethod)] public static uint ToArgb32(uint packedRgba) { - // packedRgba = [aa bb gg rr] - // ROL(8, packedRgba): + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] return (packedRgba << 8) | (packedRgba >> 24); } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } } - public static class Argb32 + public static class FromArgb32 { /// - /// Converts a packed to . + /// Converts a packed to . /// [MethodImpl(InliningOptions.ShortMethod)] public static uint ToRgba32(uint packedArgb) { - // packedArgb = [bb gg rr aa] - // ROR(8, packedArgb): + // packedArgb = [bb gg rr aa] + // ROR(8, packedArgb) = [aa bb gg rr] return (packedArgb >> 8) | (packedArgb << 24); } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedArgb) + { + // packedArgb = [bb gg rr aa] + // REVERSE(packedArgb) = [aa rr gg bb] + return BinaryPrimitives.ReverseEndianness(packedArgb); + } + } + + public static class FromBgra32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedBgra) + { + // packedBgra = [aa rr gg bb] + // REVERSE(packedBgra) = [bb gg rr aa] + return BinaryPrimitives.ReverseEndianness(packedBgra); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToRgba32(uint packedBgra) + { + // packedRgba = [aa rr gg bb] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 rr 00 bb] + // tmp3=ROL(16, tmp2) = [00 bb 00 rr] + // tmp1 + tmp3 = [aa bb gg rr] + uint tmp1 = packedBgra & 0xFF00FF00; + uint tmp2 = packedBgra & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 02b80de9b4..ad5aee8c7c 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -178,27 +178,5 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromScaledVector4(sp.ToScaledVector4()); } } - - /// - /// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size. - /// Throwing an if the condition is not met. - /// - /// The source element type - /// The destination element type - /// The source span - /// The source parameter name - /// The destination span - /// The destination parameter name - /// The minimum length - protected internal static void GuardSpans( - ReadOnlySpan source, - string sourceParamName, - Span destination, - string destinationParamName, - int minLength) - { - Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); - Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 1be8347c3d..424020e2f2 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < this.Count; i++) { uint s = Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); } } @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < this.Count; i++) { uint s = Unsafe.Add(ref dBase, i); - Unsafe.Add(ref dBase, i) = PixelConverter.Rgba32.ToArgb32(s); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs index 83c4e34f2f..9b32f7aeee 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -4,7 +4,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.PixelFormats { - public class PixelConverterTests + public abstract class PixelConverterTests { public static readonly TheoryData RgbaData = new TheoryData @@ -23,34 +23,103 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { 67, 71, 101, 109 } }; - [Theory] - [MemberData(nameof(RgbaData))] - public void Rgba32ToArgb32(byte r, byte g, byte b, byte a) + public class FromRgba32 : PixelConverterTests { - Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToArgb32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + } + + public class FromArgb32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); - // Act: - uint actualPacked = PixelConverter.Rgba32.ToArgb32(s.PackedValue); + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToRgba32(s.PackedValue); - // Assert: - uint expectedPacked = ReferenceImplementations.ToArgb32(s).PackedValue; + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; - Assert.Equal(expectedPacked, actualPacked); + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } } - [Theory] - [MemberData(nameof(RgbaData))] - public void Argb32ToRgba32(byte r, byte g, byte b, byte a) + public class FromBgra32 : PixelConverterTests { - Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); - // Act: - uint actualPacked = PixelConverter.Argb32.ToRgba32(s.PackedValue); + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToArgb32(s.PackedValue); - // Assert: - uint expectedPacked = ReferenceImplementations.ToRgba32(s).PackedValue; + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; - Assert.Equal(expectedPacked, actualPacked); + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToRgba32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } } @@ -85,66 +154,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats d.A = a; return d; } - - public static Argb32 ToArgb32(Rgba32 s) - { - Argb32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Argb32 ToArgb32(Bgra32 s) - { - Argb32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Rgba32 ToRgba32(Argb32 s) - { - Rgba32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Rgba32 ToRgba32(Bgra32 s) - { - Rgba32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Bgra32 ToBgra32(Rgba32 s) - { - Bgra32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } - - public static Bgra32 ToBgra32(Argb32 s) - { - Bgra32 d = default; - d.R = s.R; - d.G = s.G; - d.B = s.B; - d.A = s.A; - return d; - } } } } \ No newline at end of file From d5cae6987bffbba1de98269842497a548429a5ec Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 23 Oct 2018 23:34:24 +0200 Subject: [PATCH 074/238] disappointing benchmark for Rgba32 -> Bgra32 --- .../PixelConversion_Rgba32_To_Argb32.cs | 278 +++++++++++++ .../PixelConversion_Rgba32_To_Bgra32.cs | 393 ++++++++++++++++++ 2 files changed, 671 insertions(+) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs new file mode 100644 index 0000000000..5190145276 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs @@ -0,0 +1,278 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_Rgba32_To_Argb32 + { + private Rgba32[] source; + + private Argb32[] dest; + + [Params(64)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.source = new Rgba32[this.Count]; + this.dest = new Argb32[this.Count]; + } + + [Benchmark(Baseline = true)] + public void Default() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Default_GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [Benchmark] + public void Default_Generic() + { + Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void Default_Group2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 2; i += 2) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + Rgba32 s1 = Unsafe.Add(ref s0, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + d0.FromRgba32(s0); + Unsafe.Add(ref d0, 1).FromRgba32(s1); + } + } + + + [Benchmark] + public void Default_Group4() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); + ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [Benchmark] + public void Default_Group4_ManualInline_V1() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); + ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); + ref Argb32 d3 = ref Unsafe.Add(ref d2, 1); + + d0.R = s0.R; + d0.G = s0.G; + d0.B = s0.B; + d0.A = s0.A; + + d1.R = s1.R; + d1.G = s1.G; + d1.B = s1.B; + d1.A = s1.A; + + d2.R = s2.R; + d2.G = s2.G; + d2.B = s2.B; + d2.A = s2.A; + + d3.R = s3.R; + d3.G = s3.G; + d3.B = s3.B; + d3.A = s3.A; + } + } + + [Benchmark] + public void Default_Group4_ManualInline_V2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); + ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); + ref Argb32 d3 = ref Unsafe.Add(ref d2, 1); + + d0.R = s0.R; + d1.R = s1.R; + d2.R = s2.R; + d3.R = s3.R; + + d0.G = s0.G; + d1.G = s1.G; + d2.G = s2.G; + d3.G = s3.G; + + d0.B = s0.B; + d1.B = s1.B; + d2.B = s2.B; + d3.B = s3.B; + + d0.A = s0.A; + d1.A = s1.A; + d2.A = s2.A; + d3.A = s3.A; + } + } + + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Group4GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref TPixel d0 = ref Unsafe.Add(ref dBase, i); + ref TPixel d1 = ref Unsafe.Add(ref d0, 1); + ref TPixel d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [Benchmark] + public void Default_Group4_Generic() + { + Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void BitOps() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = FromRgba32.ToArgb32(s); + } + } + + [Benchmark] + public void BitOps_GroupAsULong() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + lo = FromRgba32.ToArgb32(lo); + hi = FromRgba32.ToArgb32(hi); + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs new file mode 100644 index 0000000000..9e638dbcc4 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -0,0 +1,393 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tuples; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + //[MonoJob] + [RyuJitX64Job] + public class PixelConversion_Rgba32_To_Bgra32 + { + private Rgba32[] source; + + private Bgra32[] dest; + + [StructLayout(LayoutKind.Sequential)] + struct Tuple4OfUInt32 + { + public uint V0, V1, V2, V3; + + public void ConvertMe() + { + this.V0 = FromRgba32.ToBgra32(this.V0); + this.V1 = FromRgba32.ToBgra32(this.V1); + this.V2 = FromRgba32.ToBgra32(this.V2); + this.V3 = FromRgba32.ToBgra32(this.V3); + } + } + + [Params(64)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.source = new Rgba32[this.Count]; + this.dest = new Bgra32[this.Count]; + } + + [Benchmark(Baseline = true)] + public void Default() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Default_GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [Benchmark] + public void Default_Generic() + { + Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void Default_Group2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 2; i+=2) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + Rgba32 s1 = Unsafe.Add(ref s0, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + d0.FromRgba32(s0); + Unsafe.Add(ref d0, 1).FromRgba32(s1); + } + } + + [Benchmark] + public void Default_Group4() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); + ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Group4GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref TPixel d0 = ref Unsafe.Add(ref dBase, i); + ref TPixel d1 = ref Unsafe.Add(ref d0, 1); + ref TPixel d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [Benchmark] + public void Default_Group4_Generic() + { + Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + //[Benchmark] + public void Default_Group8() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + ref Rgba32 s3 = ref Unsafe.Add(ref s1, 1); + + ref Rgba32 s4 = ref Unsafe.Add(ref s3, 1); + ref Rgba32 s5 = ref Unsafe.Add(ref s4, 1); + ref Rgba32 s6 = ref Unsafe.Add(ref s5, 1); + Rgba32 s7 = Unsafe.Add(ref s6, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); + ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); + ref Bgra32 d3 = ref Unsafe.Add(ref d2, 1); + ref Bgra32 d4 = ref Unsafe.Add(ref d3, 1); + + ref Bgra32 d5 = ref Unsafe.Add(ref d4, 1); + ref Bgra32 d6 = ref Unsafe.Add(ref d5, 1); + + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + d3.FromRgba32(s3); + + d4.FromRgba32(s4); + d5.FromRgba32(s5); + d6.FromRgba32(s6); + Unsafe.Add(ref d6, 1).FromRgba32(s7); + } + } + + [Benchmark] + public void BitOps() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = FromRgba32.ToBgra32(s); + } + } + + [Benchmark] + public void Bitops_Tuple() + { + ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + ref Tuple4OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 4; i++) + { + ref Tuple4OfUInt32 d = ref Unsafe.Add(ref dBase, i); + d = Unsafe.Add(ref sBase, i); + d.ConvertMe(); + } + } + + [Benchmark] + public void Bitops_SingleTuple() + { + ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + + for (int i = 0; i < this.Count / 4; i++) + { + Unsafe.Add(ref sBase, i).ConvertMe(); + } + } + + [Benchmark] + public void Bitops_Simd() + { + ref Octet.OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + ref Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 8; i++) + { + BitopsSimdImpl(ref Unsafe.Add(ref sBase, i), ref Unsafe.Add(ref dBase, i)); + } + } + + [StructLayout(LayoutKind.Sequential)] + struct B + { + public uint tmp2, tmp5, tmp8, tmp11, tmp14, tmp17, tmp20, tmp23; + } + + [StructLayout(LayoutKind.Sequential)] + struct C + { + public uint tmp3, tmp6, tmp9, tmp12, tmp15, tmp18, tmp21, tmp24; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void BitopsSimdImpl(ref Octet.OfUInt32 s, ref Octet.OfUInt32 d) + { + Vector sVec = Unsafe.As>(ref s); + Vector aMask = new Vector(0xFF00FF00); + Vector bMask = new Vector(0x00FF00FF); + + Vector aa = sVec & aMask; + Vector bb = sVec & bMask; + + B b = Unsafe.As, B>(ref bb); + + C c = default; + + c.tmp3 = (b.tmp2 << 16) | (b.tmp2 >> 16); + c.tmp6 = (b.tmp5 << 16) | (b.tmp5 >> 16); + c.tmp9 = (b.tmp8 << 16) | (b.tmp8 >> 16); + c.tmp12 = (b.tmp11 << 16) | (b.tmp11 >> 16); + c.tmp15 = (b.tmp14 << 16) | (b.tmp14 >> 16); + c.tmp18 = (b.tmp17 << 16) | (b.tmp17 >> 16); + c.tmp21 = (b.tmp20 << 16) | (b.tmp20 >> 16); + c.tmp24 = (b.tmp23 << 16) | (b.tmp23 >> 16); + + Vector cc = Unsafe.As>(ref c); + Vector dd = aa + cc; + + d = Unsafe.As, Octet.OfUInt32>(ref dd); + } + + //[Benchmark] + public void BitOps_Group2() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + ref uint s0 = ref Unsafe.Add(ref sBase, i); + uint s1 = Unsafe.Add(ref s0, 1); + + ref uint d0 = ref Unsafe.Add(ref dBase, i); + d0 = FromRgba32.ToBgra32(s0); + Unsafe.Add(ref d0, 1) = FromRgba32.ToBgra32(s1); + } + } + + [Benchmark] + public void BitOps_GroupAsULong() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + lo = FromRgba32.ToBgra32(lo); + hi = FromRgba32.ToBgra32(hi); + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + //[Benchmark] + public void BitOps_GroupAsULong_V2() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + + uint tmp1 = lo & 0xFF00FF00; + uint tmp4 = hi & 0xFF00FF00; + + uint tmp2 = lo & 0x00FF00FF; + uint tmp5 = hi & 0x00FF00FF; + + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + uint tmp6 = (tmp5 << 16) | (tmp5 >> 16); + + lo = tmp1 + tmp3; + hi = tmp4 + tmp6; + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // ----------------------- |------ |----------:|----------:|----------:|-------:| + // Default | 64 | 107.13 ns | 0.7752 ns | 0.6872 ns | 1.00 | + // Default_Generic | 64 | 113.78 ns | 0.7713 ns | 0.6022 ns | 1.06 | + // Default_Group2 | 64 | 43.72 ns | 0.1711 ns | 0.1600 ns | 0.41 | + // Default_Group4 | 64 | 23.47 ns | 0.1901 ns | 0.1588 ns | 0.22 | + // Default_Group4_Generic | 64 | 32.46 ns | 0.4297 ns | 0.4019 ns | 0.30 | + // Bitops_Tuple | 64 | 77.71 ns | 0.2779 ns | 0.2599 ns | 0.73 | + // Bitops_SingleTuple | 64 | 58.64 ns | 0.4511 ns | 0.4220 ns | 0.55 | + // Bitops_Simd | 64 | 110.58 ns | 0.4686 ns | 0.4383 ns | 1.03 | + } +} \ No newline at end of file From f52be32abafa7d164d9c31f2ce4851576c667ac9 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:13:17 -0700 Subject: [PATCH 075/238] Cross target NET472 and enable extended intrinisics behind SUPPORTS_EXTENDED_INTRINSICS symbol --- .../Common/Helpers/SimdUtils.ExtendedIntrinsics.cs | 4 +--- src/ImageSharp/Common/Helpers/SimdUtils.cs | 4 ++-- src/ImageSharp/Common/Helpers/TestHelpers.cs | 6 +++++- src/ImageSharp/ImageSharp.csproj | 13 +++++++++---- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 2 +- tests/ImageSharp.Tests/RunExtendedTests.cmd | 2 ++ 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index e0d6187dca..2ac577264c 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -20,8 +19,7 @@ namespace SixLabors.ImageSharp public static class ExtendedIntrinsics { public static bool IsAvailable { get; } = -#if NETCOREAPP2_1 - // TODO: Also available in .NET 4.7.2, we need to add a build target! +#if SUPPORTS_EXTENDED_INTRINSICS Vector.IsHardwareAccelerated; #else false; diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 71eb88b1d1..a989cc8752 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); -#if NETCOREAPP2_1 +#if SUPPORTS_EXTENDED_INTRINSICS ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); #else BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); -#if NETCOREAPP2_1 +#if SUPPORTS_EXTENDED_INTRINSICS ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); #else BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); diff --git a/src/ImageSharp/Common/Helpers/TestHelpers.cs b/src/ImageSharp/Common/Helpers/TestHelpers.cs index 45ef7706dd..fd16a577ab 100644 --- a/src/ImageSharp/Common/Helpers/TestHelpers.cs +++ b/src/ImageSharp/Common/Helpers/TestHelpers.cs @@ -13,8 +13,12 @@ namespace SixLabors.ImageSharp.Common.Helpers /// Only intended to be used in tests! /// internal const string ImageSharpBuiltAgainst = -#if NETCOREAPP2_1 +#if NET472 + "netfx4.7.2"; +#elif NETCOREAPP2_1 "netcoreapp2.1"; +#elif NETSTANDARD1_3 + "netstandard1.3"; #else "netstandard2.0"; #endif diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 8d2ad2abe3..29d29d50d8 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,7 +5,7 @@ $(packageversion) 0.0.1 Six Labors and contributors - netstandard1.3;netstandard2.0;netcoreapp2.1 + netstandard1.3;netstandard2.0;netcoreapp2.1;net472 true true SixLabors.ImageSharp @@ -31,9 +31,15 @@ IOperation Latest + + + $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS + + + @@ -43,15 +49,14 @@ - - - + + ..\..\ImageSharp.ruleset SixLabors.ImageSharp diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 5d163917cd..04a6802005 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,6 +1,6 @@  - net462;net471;netcoreapp2.1 + net462;net472;netcoreapp2.1 True latest full diff --git a/tests/ImageSharp.Tests/RunExtendedTests.cmd b/tests/ImageSharp.Tests/RunExtendedTests.cmd index 481e5fb3d8..c2f4b9f537 100644 --- a/tests/ImageSharp.Tests/RunExtendedTests.cmd +++ b/tests/ImageSharp.Tests/RunExtendedTests.cmd @@ -5,3 +5,5 @@ dotnet xunit -nobuild -c Release -f net47 dotnet xunit -nobuild -c Release -f net47 -x86 dotnet xunit -nobuild -c Release -f net471 dotnet xunit -nobuild -c Release -f net471 -x86 +dotnet xunit -nobuild -c Release -f net472 +dotnet xunit -nobuild -c Release -f net472 -x86 From 0e1efba34198e2a3cb204e53ce000c88f8f1bdbf Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:30:30 -0700 Subject: [PATCH 076/238] Use Array.Empty --- .../Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs | 6 +++--- .../ICC/DataWriter/IccDataWriter.PrimitivesTests.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs index 38a2f4522c..77a913b14e 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// Initializes a new instance of the class. /// public IccCurveTagDataEntry() - : this(new float[0], IccProfileTag.Unknown) + : this(Array.Empty(), IccProfileTag.Unknown) { } @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// Tag Signature public IccCurveTagDataEntry(IccProfileTag tagSignature) - : this(new float[0], tagSignature) + : this(Array.Empty(), tagSignature) { } @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc public IccCurveTagDataEntry(float[] curveData, IccProfileTag tagSignature) : base(IccTypeSignature.Curve, tagSignature) { - this.CurveData = curveData ?? new float[0]; + this.CurveData = curveData ?? Array.Empty(); } /// diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs index 56a4f8c0ca..845a149b5d 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Icc byte[] output = writer.GetData(); Assert.Equal(0, count); - Assert.Equal(new byte[0], output); + Assert.Equal(Array.Empty(), output); } [Fact] @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Icc byte[] output = writer.GetData(); Assert.Equal(0, count); - Assert.Equal(new byte[0], output); + Assert.Equal(Array.Empty(), output); } [Theory] From de0956295ad65c94f2d73cfbd20f52e7550a6306 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:40:24 -0700 Subject: [PATCH 077/238] [Exif] Eliminate invalidTag list allocation when there are no invalid tags --- .../MetaData/Profiles/Exif/ExifProfile.cs | 12 +++++++++-- .../MetaData/Profiles/Exif/ExifReader.cs | 20 ++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index b48b146f11..32c1796d4c 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { this.Parts = ExifParts.All; this.data = data; - this.InvalidTags = new List(); + this.InvalidTags = Array.Empty(); } /// @@ -289,7 +289,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.values = reader.ReadValues(); - this.InvalidTags = new List(reader.InvalidTags); + if (reader.InvalidTags.Count > 0) + { + this.InvalidTags = new List(reader.InvalidTags); + } + else + { + this.InvalidTags = Array.Empty(); + } + this.thumbnailOffset = (int)reader.ThumbnailOffset; this.thumbnailLength = (int)reader.ThumbnailLength; } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 5f95499088..3326c3217a 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Primitives; @@ -19,7 +18,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// internal sealed class ExifReader { - private readonly List invalidTags = new List(); + private List invalidTags; private readonly byte[] exifData; private int position; private Endianness endianness = Endianness.BigEndian; @@ -38,7 +37,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets the invalid tags. /// - public IReadOnlyList InvalidTags => this.invalidTags; + public IReadOnlyList InvalidTags => this.invalidTags ?? (IReadOnlyList)Array.Empty(); /// /// Gets the thumbnail length in the byte stream @@ -338,7 +337,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif // Ensure that the new index does not overrun the data if (newIndex > int.MaxValue) { - this.invalidTags.Add(tag); + this.AddInvalidTag(tag); exifValue = default; @@ -349,7 +348,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif if (this.RemainingLength < size) { - this.invalidTags.Add(tag); + this.AddInvalidTag(tag); + this.position = oldIndex; exifValue = default; @@ -372,6 +372,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return true; } + private void AddInvalidTag(ExifTag tag) + { + if (this.invalidTags == null) + { + this.invalidTags = new List(); + } + + this.invalidTags.Add(tag); + } + private TEnum ToEnum(int value, TEnum defaultValue) where TEnum : struct { From 2293494a77437ff004efdc4c3715049ca9bb37de Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:45:47 -0700 Subject: [PATCH 078/238] Update IccProfile Entries to Array --- src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs | 11 ++++++----- src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs | 4 ++-- .../MetaData/Profiles/ICC/IccReaderTests.cs | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 72665bc69c..1d3b27c5ec 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Security.Cryptography; namespace SixLabors.ImageSharp.MetaData.Profiles.Icc @@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// The backing file for the property /// - private List entries; + private IccTagDataEntry[] entries; /// /// ICC profile header @@ -52,7 +53,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc Guard.NotNull(entries, nameof(entries)); this.header = header; - this.entries = new List(entries); + this.entries = entries.ToArray(); } /// @@ -85,7 +86,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// Gets the actual profile data /// - public List Entries + public IccTagDataEntry[] Entries { get { @@ -212,12 +213,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc if (this.data is null) { - this.entries = new List(); + this.entries = Array.Empty(); return; } var reader = new IccReader(); - this.entries = new List(reader.ReadTagData(this.data)); + this.entries = reader.ReadTagData(this.data); } } } \ No newline at end of file diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs index b476e31955..91a3bba549 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs @@ -68,12 +68,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } } - private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List entries) + private IccTagTableEntry[] WriteTagData(IccDataWriter writer, IccTagDataEntry[] entries) { IEnumerable> grouped = entries.GroupBy(t => t); // (Header size) + (entry count) + (nr of entries) * (size of table entry) - writer.SetIndex(128 + 4 + (entries.Count * 12)); + writer.SetIndex(128 + 4 + (entries.Length * 12)); var table = new List(); foreach (IGrouping group in grouped) diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs index b3215ee7ae..c91076afc9 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Icc IccProfile output = reader.Read(IccTestDataProfiles.Header_Random_Array); - Assert.Equal(0, output.Entries.Count); + Assert.Equal(0, output.Entries.Length); Assert.NotNull(output.Header); IccProfileHeader header = output.Header; @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Icc IccProfile output = reader.Read(IccTestDataProfiles.Profile_Random_Array); - Assert.Equal(2, output.Entries.Count); + Assert.Equal(2, output.Entries.Length); Assert.True(ReferenceEquals(output.Entries[0], output.Entries[1])); } From 41b5ef3061a3507c26e7c846a9e27bae2b3b9f18 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:57:30 -0700 Subject: [PATCH 079/238] Eliminate an allocation when cloning a valid ExifProfile --- src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 32c1796d4c..6890cc5358 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -63,7 +63,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.Parts = other.Parts; this.thumbnailLength = other.thumbnailLength; this.thumbnailOffset = other.thumbnailOffset; - this.InvalidTags = new List(other.InvalidTags); + + if (other.InvalidTags.Count > 0) + { + this.InvalidTags = new List(other.InvalidTags); + } + else + { + this.InvalidTags = Array.Empty(); + } + if (other.values != null) { this.values = new List(other.Values.Count); From a80335d9e0a3af12db6f56bb94ccfbb4c354f5a9 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 17:58:00 -0700 Subject: [PATCH 080/238] Eliminate allocation in invalid icc profile --- src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs index da47b565e3..9f9d373ae1 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; namespace SixLabors.ImageSharp.MetaData.Profiles.Icc @@ -126,7 +127,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc // A normal profile usually has 5-15 entries if (tagCount > 100) { - return new IccTagTableEntry[0]; + return Array.Empty(); } var table = new List((int)tagCount); From 880ee68248c93d108e2c3598f78d9fc28ddbe2a2 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:00:08 -0700 Subject: [PATCH 081/238] Update appveyor target frameworks --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 821fd427c8..34c733e68d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,7 +15,7 @@ environment: - target_framework: net471 is_32bit: False - - target_framework: net471 + - target_framework: net472 is_32bit: True - target_framework: net462 From bed5c6350581fba367162ee738c7ed5caae3fd4b Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:00:41 -0700 Subject: [PATCH 082/238] Update appveyor target frameworks (64bit) --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 34c733e68d..2cc5182d39 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,7 +12,7 @@ environment: - target_framework: netcoreapp2.1 is_32bit: True - - target_framework: net471 + - target_framework: net472 is_32bit: False - target_framework: net472 From e2fe2b148b25dc47db0e6012639f3f164b38a74b Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:07:24 -0700 Subject: [PATCH 083/238] Update IccProfile constructor --- src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 1d3b27c5ec..5d75a6df9d 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections.Generic; -using System.Linq; using System.Security.Cryptography; namespace SixLabors.ImageSharp.MetaData.Profiles.Icc @@ -47,13 +45,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// The profile header /// The actual profile data - internal IccProfile(IccProfileHeader header, IEnumerable entries) + internal IccProfile(IccProfileHeader header, IccTagDataEntry[] entries) { - Guard.NotNull(header, nameof(header)); - Guard.NotNull(entries, nameof(entries)); - - this.header = header; - this.entries = entries.ToArray(); + this.header = header ?? throw new ArgumentNullException(nameof(header)); + this.entries = entries ?? throw new ArgumentNullException(nameof(entries)); } /// From 5771f96382f882f0782b9221b98250977ba6cba8 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:16:21 -0700 Subject: [PATCH 084/238] [Exif] Make allowedParts and values readonly --- src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs index ade373341e..9079526d5a 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs @@ -17,8 +17,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Which parts will be written. /// - private ExifParts allowedParts; - private IList values; + private readonly ExifParts allowedParts; + private readonly IList values; private List dataOffsets; private readonly List ifdIndexes; private readonly List exifIndexes; From 3ac47cb4ed040efc8eb9fa352605784545292c97 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 23 Oct 2018 18:22:40 -0700 Subject: [PATCH 085/238] Use ternary operator --- .../MetaData/Profiles/Exif/ExifProfile.cs | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 6890cc5358..37ceaf10f6 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -64,14 +64,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.thumbnailLength = other.thumbnailLength; this.thumbnailOffset = other.thumbnailOffset; - if (other.InvalidTags.Count > 0) - { - this.InvalidTags = new List(other.InvalidTags); - } - else - { - this.InvalidTags = Array.Empty(); - } + this.InvalidTags = other.InvalidTags.Count > 0 + ? new List(other.InvalidTags) + : (IReadOnlyList)Array.Empty(); if (other.values != null) { @@ -298,14 +293,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.values = reader.ReadValues(); - if (reader.InvalidTags.Count > 0) - { - this.InvalidTags = new List(reader.InvalidTags); - } - else - { - this.InvalidTags = Array.Empty(); - } + this.InvalidTags = reader.InvalidTags.Count > 0 + ? new List(reader.InvalidTags) + : (IReadOnlyList)Array.Empty(); this.thumbnailOffset = (int)reader.ThumbnailOffset; this.thumbnailLength = (int)reader.ThumbnailLength; From 3dde4917124c90c891b790ec0806aa4c61e978f7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 24 Oct 2018 01:49:26 +0200 Subject: [PATCH 086/238] Fixed the benchmarks. All results make sense now! (cherry picked from commit 0d79d4eb58fa1002979f4157eb18c6291a164b06) --- .../PixelConversion_Rgba32_To_Argb32.cs | 128 ++---------------- .../PixelConversion_Rgba32_To_Bgra32.cs | 33 +++-- 2 files changed, 29 insertions(+), 132 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs index 5190145276..40893914e1 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref this.source[0]; ref Argb32 dBase = ref this.dest[0]; - for (int i = 0; i < this.Count / 2; i += 2) + for (int i = 0; i < this.Count; i += 2) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); Rgba32 s1 = Unsafe.Add(ref s0, 1); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref this.source[0]; ref Argb32 dBase = ref this.dest[0]; - for (int i = 0; i < this.Count / 4; i += 4) + for (int i = 0; i < this.Count; i += 4) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); @@ -98,119 +98,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion Unsafe.Add(ref d2, 1).FromRgba32(s3); } } - - [Benchmark] - public void Default_Group4_ManualInline_V1() - { - ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; - - for (int i = 0; i < this.Count / 4; i += 4) - { - ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); - ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); - ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); - Rgba32 s3 = Unsafe.Add(ref s2, 1); - - ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); - ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); - ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); - ref Argb32 d3 = ref Unsafe.Add(ref d2, 1); - - d0.R = s0.R; - d0.G = s0.G; - d0.B = s0.B; - d0.A = s0.A; - - d1.R = s1.R; - d1.G = s1.G; - d1.B = s1.B; - d1.A = s1.A; - - d2.R = s2.R; - d2.G = s2.G; - d2.B = s2.B; - d2.A = s2.A; - - d3.R = s3.R; - d3.G = s3.G; - d3.B = s3.B; - d3.A = s3.A; - } - } - - [Benchmark] - public void Default_Group4_ManualInline_V2() - { - ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; - - for (int i = 0; i < this.Count / 4; i += 4) - { - ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); - ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); - ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); - Rgba32 s3 = Unsafe.Add(ref s2, 1); - - ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); - ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); - ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); - ref Argb32 d3 = ref Unsafe.Add(ref d2, 1); - - d0.R = s0.R; - d1.R = s1.R; - d2.R = s2.R; - d3.R = s3.R; - - d0.G = s0.G; - d1.G = s1.G; - d2.G = s2.G; - d3.G = s3.G; - - d0.B = s0.B; - d1.B = s1.B; - d2.B = s2.B; - d3.B = s3.B; - - d0.A = s0.A; - d1.A = s1.A; - d2.A = s2.A; - d3.A = s3.A; - } - } - - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void Group4GenericImpl(ReadOnlySpan source, Span dest) - where TPixel : struct, IPixel - { - ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); - ref TPixel dBase = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < source.Length / 4; i += 4) - { - ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); - ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); - ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); - Rgba32 s3 = Unsafe.Add(ref s2, 1); - - ref TPixel d0 = ref Unsafe.Add(ref dBase, i); - ref TPixel d1 = ref Unsafe.Add(ref d0, 1); - ref TPixel d2 = ref Unsafe.Add(ref d1, 1); - - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - Unsafe.Add(ref d2, 1).FromRgba32(s3); - } - } - - [Benchmark] - public void Default_Group4_Generic() - { - Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); - } - + [Benchmark] public void BitOps() { @@ -274,5 +162,15 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion return tmp1 + tmp3; } } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------------- |------ |----------:|----------:|----------:|-------:| + // Default | 64 | 107.33 ns | 1.0633 ns | 0.9426 ns | 1.00 | + // Default_Generic | 64 | 111.15 ns | 0.3789 ns | 0.3544 ns | 1.04 | + // Default_Group2 | 64 | 90.36 ns | 0.7779 ns | 0.6896 ns | 0.84 | + // Default_Group4 | 64 | 82.39 ns | 0.2726 ns | 0.2550 ns | 0.77 | + // BitOps | 64 | 39.25 ns | 0.3266 ns | 0.2895 ns | 0.37 | + // BitOps_GroupAsULong | 64 | 41.80 ns | 0.2227 ns | 0.2083 ns | 0.39 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs index 9e638dbcc4..9cf16ea196 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref this.source[0]; ref Bgra32 dBase = ref this.dest[0]; - for (int i = 0; i < this.Count / 2; i+=2) + for (int i = 0; i < this.Count; i+=2) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); Rgba32 s1 = Unsafe.Add(ref s0, 1); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref this.source[0]; ref Bgra32 dBase = ref this.dest[0]; - for (int i = 0; i < this.Count / 4; i += 4) + for (int i = 0; i < this.Count; i += 4) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion Unsafe.Add(ref d2, 1).FromRgba32(s3); } } - + [MethodImpl(MethodImplOptions.NoInlining)] private static void Group4GenericImpl(ReadOnlySpan source, Span dest) where TPixel : struct, IPixel @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); ref TPixel dBase = ref MemoryMarshal.GetReference(dest); - for (int i = 0; i < source.Length / 4; i += 4) + for (int i = 0; i < source.Length; i += 4) { ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } } - [Benchmark] + //[Benchmark] public void Default_Group4_Generic() { Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); @@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } } - [Benchmark] + //[Benchmark] public void Bitops_SingleTuple() { ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion } } - [Benchmark] + //[Benchmark] public void Bitops_Simd() { ref Octet.OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); @@ -379,15 +379,14 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | - // ----------------------- |------ |----------:|----------:|----------:|-------:| - // Default | 64 | 107.13 ns | 0.7752 ns | 0.6872 ns | 1.00 | - // Default_Generic | 64 | 113.78 ns | 0.7713 ns | 0.6022 ns | 1.06 | - // Default_Group2 | 64 | 43.72 ns | 0.1711 ns | 0.1600 ns | 0.41 | - // Default_Group4 | 64 | 23.47 ns | 0.1901 ns | 0.1588 ns | 0.22 | - // Default_Group4_Generic | 64 | 32.46 ns | 0.4297 ns | 0.4019 ns | 0.30 | - // Bitops_Tuple | 64 | 77.71 ns | 0.2779 ns | 0.2599 ns | 0.73 | - // Bitops_SingleTuple | 64 | 58.64 ns | 0.4511 ns | 0.4220 ns | 0.55 | - // Bitops_Simd | 64 | 110.58 ns | 0.4686 ns | 0.4383 ns | 1.03 | + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------------- |------ |----------:|----------:|----------:|-------:| + // Default | 64 | 106.84 ns | 0.4042 ns | 0.3583 ns | 1.00 | + // Default_Generic | 64 | 113.11 ns | 0.6998 ns | 0.6203 ns | 1.06 | + // Default_Group2 | 64 | 86.81 ns | 0.4976 ns | 0.4654 ns | 0.81 | + // Default_Group4 | 64 | 83.53 ns | 1.3826 ns | 1.2933 ns | 0.78 | + // BitOps | 64 | 54.23 ns | 0.1920 ns | 0.1796 ns | 0.51 | + // Bitops_Tuple | 64 | 73.45 ns | 0.5475 ns | 0.4853 ns | 0.69 | + // BitOps_GroupAsULong | 64 | 64.28 ns | 0.4046 ns | 0.3785 ns | 0.60 | } } \ No newline at end of file From e70e7d4ab7b06fab386084c9878c72d4f85b3561 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 25 Oct 2018 02:04:55 +0200 Subject: [PATCH 087/238] Optimized bulk conversion for common pixel types --- .../Argb32.PixelOperations.Generated.cs | 117 ++++++++++++++---- .../Bgr24.PixelOperations.Generated.cs | 37 ++++++ .../Bgra32.PixelOperations.Generated.cs | 111 +++++++++++++---- .../Gray16.PixelOperations.Generated.cs | 12 ++ .../Gray8.PixelOperations.Generated.cs | 12 ++ .../Rgb24.PixelOperations.Generated.cs | 37 ++++++ .../Rgb48.PixelOperations.Generated.cs | 12 ++ .../Rgba32.PixelOperations.Generated.cs | 76 +++++++++--- .../Rgba64.PixelOperations.Generated.cs | 12 ++ .../Generated/_Common.ttinclude | 100 ++++++++++++++- .../Rgba32.PixelOperations.cs | 20 +-- .../RgbaVector.PixelOperations.cs | 8 +- .../PixelFormats/PixelOperations{TPixel}.cs | 82 ++++++++++-- 13 files changed, 537 insertions(+), 99 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 09f10716e2..e6b8922e9d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,109 +35,167 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - + /// - internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); } } - + /// - internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); + } + } + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); + } + } - dp.FromArgb32(sp); + /// + internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); } } /// - internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } } /// - internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); dp.FromArgb32(sp); } @@ -143,6 +204,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +222,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index f8c61e4fac..9b1740013d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,15 +35,42 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +88,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +106,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +160,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +178,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +196,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 9bddd18e9c..37d6b72d71 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,32 +35,104 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + /// - internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); + } + } - dp.FromBgra32(sp); + /// + internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); + } + } + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); + } + } + + /// + internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); } } /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +186,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -119,23 +197,6 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp.FromBgra32(sp); - } - } - - /// - internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) - { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < sourcePixels.Length; i++) - { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.FromBgra32(sp); } } @@ -143,6 +204,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +222,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index 31c5755345..638db1d0d8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,6 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -41,6 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +135,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 14a2c858cf..6bf0693c2c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,6 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -41,6 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +135,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index f8b80020ec..6ff87eb385 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,15 +35,42 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +88,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +106,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +124,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +160,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +178,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +196,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 5741b10706..9b4584d767 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,6 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -41,6 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +135,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index 9f7b624c07..8e15ca1f4d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,58 +35,88 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); } } - + /// - internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); + } + } + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); for (int i = 0; i < sourcePixels.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); + } + } - dp.FromRgba32(sp); + /// + internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); } } /// - internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourcePixels.Length; i++) { ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); dp.FromRgba32(sp); } @@ -92,6 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +143,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +161,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +179,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +197,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index 411178b825..caaba78094 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -4,6 +4,8 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -32,6 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -41,6 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -58,6 +63,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -75,6 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -92,6 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -109,6 +117,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -126,6 +135,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -143,6 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -160,6 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index bc23edb015..4501f4972e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -9,10 +9,17 @@ // using System; +using System.Buffers; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <#+ - static readonly string[] CommonPixelTypeNames = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + static readonly string[] CommonPixelTypes = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + + static readonly string[] Optimized32BitTypes = { "Rgba32", "Argb32", "Bgra32" }; + + // Types with Rgba32-combatible to/from Vector4 conversion + static readonly string[] Rgba32CompatibleTypes = { "Argb32", "Bgra32", "Rgb24", "Bgr24" }; void GenerateDefaultSelfConversionMethods(string pixelType) { @@ -21,6 +28,7 @@ using System.Runtime.InteropServices; /// internal override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -29,6 +37,7 @@ using System.Runtime.InteropServices; /// internal override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); @@ -44,6 +53,7 @@ using System.Runtime.InteropServices; /// internal override void To<#=toPixelType#>(Configuration configuration, ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,13 +70,97 @@ using System.Runtime.InteropServices; <#+ } + void GenerateOptimized32BitConversionMethods(string thisPixelType, string otherPixelType) + { + #> + /// + internal override void To<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=thisPixelType#>> sourcePixels, Span<<#=otherPixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As<<#=thisPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As<<#=otherPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.From<#=thisPixelType#>.To<#=otherPixelType#>(sp); + } + } + + /// + internal override void From<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=otherPixelType#>> sourcePixels, Span<<#=thisPixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As<<#=otherPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As<<#=thisPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(sp); + } + } + <#+ + } + + void GenerateRgba32CompatibleVector4ConversionMethods(string pixelType) + { + #> + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + } + + <#+ + } + void GenerateAllDefaultConversionMethods(string pixelType) { GenerateDefaultSelfConversionMethods(pixelType); - var allOtherPixelTypes = CommonPixelTypeNames.Where(p => p != pixelType); + if (Rgba32CompatibleTypes.Contains(pixelType)) + { + GenerateRgba32CompatibleVector4ConversionMethods(pixelType); + } + + var matching32BitTypes = Optimized32BitTypes.Contains(pixelType) ? + Optimized32BitTypes.Where(p => p != pixelType) : + Enumerable.Empty(); + + foreach (string destPixelType in matching32BitTypes) + { + GenerateOptimized32BitConversionMethods(pixelType, destPixelType); + } + + var otherCommonNon32Types = CommonPixelTypes + .Where(p => p != pixelType) + .Except(matching32BitTypes); - foreach (string destPixelType in allOtherPixelTypes) + foreach (string destPixelType in otherCommonNon32Types) { GenerateDefaultConvertToMethod(pixelType, destPixelType); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index 0f5ddf3729..004b25cd33 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -21,31 +21,31 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToVector4( Configuration configuration, - ReadOnlySpan sourceColors, - Span destinationVectors) + ReadOnlySpan sourcePixels, + Span destVectors) { - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - destinationVectors = destinationVectors.Slice(0, sourceColors.Length); + destVectors = destVectors.Slice(0, sourcePixels.Length); SimdUtils.BulkConvertByteToNormalizedFloat( - MemoryMarshal.Cast(sourceColors), - MemoryMarshal.Cast(destinationVectors)); + MemoryMarshal.Cast(sourcePixels), + MemoryMarshal.Cast(destVectors)); } /// internal override void FromVector4( Configuration configuration, ReadOnlySpan sourceVectors, - Span destinationColors) + Span destPixels) { - Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - destinationColors = destinationColors.Slice(0, sourceVectors.Length); + destPixels = destPixels.Slice(0, sourceVectors.Length); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( MemoryMarshal.Cast(sourceVectors), - MemoryMarshal.Cast(destinationColors)); + MemoryMarshal.Cast(destPixels)); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index cb12d944c7..bffaf57ddd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -38,12 +38,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToVector4( Configuration configuration, - ReadOnlySpan sourceColors, - Span destinationVectors) + ReadOnlySpan sourcePixels, + Span destVectors) { - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - MemoryMarshal.Cast(sourceColors).CopyTo(destinationVectors); + MemoryMarshal.Cast(sourcePixels).CopyTo(destVectors); } } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index ad5aee8c7c..3cebf7b54a 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -26,17 +27,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// A to configure internal operations /// The to the source vectors. - /// The to the destination colors. + /// The to the destination colors. internal virtual void FromVector4( Configuration configuration, ReadOnlySpan sourceVectors, - Span destinationColors) + Span destPixels) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); for (int i = 0; i < sourceVectors.Length; i++) { @@ -50,20 +51,20 @@ namespace SixLabors.ImageSharp.PixelFormats /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// A to configure internal operations - /// The to the source colors. - /// The to the destination vectors. + /// The to the source colors. + /// The to the destination vectors. internal virtual void ToVector4( Configuration configuration, - ReadOnlySpan sourceColors, - Span destinationVectors) + ReadOnlySpan sourcePixels, + Span destVectors) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); - for (int i = 0; i < sourceColors.Length; i++) + for (int i = 0; i < sourcePixels.Length; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); ref Vector4 dp = ref Unsafe.Add(ref destRef, i); @@ -178,5 +179,62 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromScaledVector4(sp.ToScaledVector4()); } } + + /// + /// Provides an efficient default implementation for and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal void RunRgba32CompatibleToVector4Conversion( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + int count = sourcePixels.Length; + + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) + { + Span tempSpan = tempBuffer.Memory.Span; + this.ToRgba32(configuration, sourcePixels, tempSpan); + + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(tempSpan), + MemoryMarshal.Cast(destVectors)); + } + } + + /// + /// Provides an efficient default implementation for and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal void RunRgba32CompatibleFromVector4Conversion( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + int count = sourceVectors.Length; + + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) + { + Span tempSpan = tempBuffer.Memory.Span; + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(tempSpan)); + + this.FromRgba32(configuration, tempSpan, destPixels); + } + } } } \ No newline at end of file From 0fc01d75f454babd74b295cd329df817a32b4b1e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 25 Oct 2018 02:43:02 +0200 Subject: [PATCH 088/238] run default implementation for small buffers --- .../PixelFormats/PixelOperations{TPixel}.cs | 63 +++++++++++++------ .../Color/Bulk/ToVector4.cs | 28 ++++++--- 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 3cebf7b54a..c3d8e23b91 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -36,15 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < sourceVectors.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromVector4(sp); - } + FromVector4DefaultImpl(sourceVectors, destPixels); } /// @@ -61,15 +53,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); - - for (int i = 0; i < sourcePixels.Length; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } + ToVector4DefaultImpl(sourcePixels, destVectors); } /// @@ -135,6 +119,7 @@ namespace SixLabors.ImageSharp.PixelFormats Span destinationColors) where TDestinationPixel : struct, IPixel { + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationColors, nameof(destinationColors)); int count = sourceColors.Length; @@ -197,6 +182,13 @@ namespace SixLabors.ImageSharp.PixelFormats int count = sourcePixels.Length; + // Not worth for small buffers: + if (count < 128) + { + ToVector4DefaultImpl(sourcePixels, destVectors); + return; + } + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) { Span tempSpan = tempBuffer.Memory.Span; @@ -225,6 +217,13 @@ namespace SixLabors.ImageSharp.PixelFormats int count = sourceVectors.Length; + // Not worth for small buffers: + if (count < 128) + { + FromVector4DefaultImpl(sourceVectors, destPixels); + return; + } + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) { Span tempSpan = tempBuffer.Memory.Span; @@ -236,5 +235,33 @@ namespace SixLabors.ImageSharp.PixelFormats this.FromRgba32(configuration, tempSpan, destPixels); } } + + [MethodImpl(InliningOptions.ShortMethod)] + private static void FromVector4DefaultImpl(ReadOnlySpan sourceVectors, Span destPixels) + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static void ToVector4DefaultImpl(ReadOnlySpan sourcePixels, Span destVectors) + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index f0fee649af..897badd9f2 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk [Params( 64, - //256, + 256, //512, //1024, 2048)] @@ -58,20 +58,25 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk d[i] = s[i].ToVector4(); } } + [Benchmark] - public void PixelOperations_Base() + public void PixelOperations_Specialized() { - new PixelOperations().ToVector4( + PixelOperations.Instance.ToVector4( this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); } + } - [Benchmark] - public void PixelOperations_Specialized() + [Config(typeof(Config.ShortClr))] + public class ToVector4_Bgra32 : ToVector4 + { + [Benchmark(Baseline = true)] + public void PixelOperations_Base() { - PixelOperations.Instance.ToVector4( + new PixelOperations().ToVector4( this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); @@ -89,7 +94,16 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); } - + + [Benchmark] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + [Benchmark(Baseline = true)] public void BasicIntrinsics256() { From d154c45007cc56cc44f29deabcdcc2de0eb44749 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 14:30:11 +0200 Subject: [PATCH 089/238] fix Gray8.ToString() --- src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs index d23fda7991..4ed5904c2b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue); /// - public override string ToString() => $"Gray8({this.PackedValue}"; + public override string ToString() => $"Gray8({this.PackedValue})"; /// [MethodImpl(InliningOptions.ShortMethod)] From b87c93e1951fa2b63be8c394b645fa68eb422d6e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 15:18:26 +0200 Subject: [PATCH 090/238] benchmakrs --- .../Color/Bulk/FromRgba32Bytes.cs | 28 ++- .../Color/Bulk/{ToXyz.cs => Rgb24Bytes.cs} | 4 +- .../Bulk/{ToXyzw.cs => ToRgba32Bytes.cs} | 16 +- .../Color/Bulk/ToVector4.cs | 169 +----------------- .../Color/Bulk/ToVector4_Bgra32.cs | 20 +++ .../Color/Bulk/ToVector4_Rgba32.cs | 164 +++++++++++++++++ .../PixelConversion_Rgba32_To_Bgra32.cs | 24 +-- 7 files changed, 232 insertions(+), 193 deletions(-) rename tests/ImageSharp.Benchmarks/Color/Bulk/{ToXyz.cs => Rgb24Bytes.cs} (94%) rename tests/ImageSharp.Benchmarks/Color/Bulk/{ToXyzw.cs => ToRgba32Bytes.cs} (87%) create mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs create mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs index 32565c23dc..b964221764 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs @@ -22,7 +22,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk private Configuration configuration; - [Params(16, 128, 1024)] + [Params( + 128, + 1024, + 2048)] public int Count { get; set; } [GlobalSetup] @@ -40,8 +43,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.Dispose(); } - [Benchmark(Baseline = true)] - public void PerElement() + //[Benchmark] + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); @@ -55,7 +58,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + [Benchmark(Baseline = true)] public void CommonBulk() { new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); @@ -68,7 +71,22 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - public class FromRgba32BytesRgba32 : FromRgba32Bytes + public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes + { + } + + public class FromRgba32Bytes_ToBgra32 : FromRgba32Bytes { + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------- |------ |-----------:|----------:|----------:|-------:| + // CommonBulk | 128 | 207.1 ns | 3.723 ns | 3.300 ns | 1.00 | + // OptimizedBulk | 128 | 166.5 ns | 1.204 ns | 1.005 ns | 0.80 | + // | | | | | | + // CommonBulk | 1024 | 1,333.9 ns | 12.426 ns | 11.624 ns | 1.00 | + // OptimizedBulk | 1024 | 974.1 ns | 18.803 ns | 16.669 ns | 0.73 | + // | | | | | | + // CommonBulk | 2048 | 2,625.4 ns | 30.143 ns | 26.721 ns | 1.00 | + // OptimizedBulk | 2048 | 1,843.0 ns | 20.505 ns | 18.177 ns | 0.70 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs index 912c3e4b2e..294baa9d51 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs @@ -10,7 +10,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - public abstract class ToXyz + public abstract class Rgb24Bytes where TPixel : struct, IPixel { private IMemoryOwner source; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.Count); } - public class ToXyz_Rgba32 : ToXyz + public class Rgb24Bytes_Rgba32 : Rgb24Bytes { } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs similarity index 87% rename from tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs index 37694f64cd..7f4b2bc41d 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs @@ -12,7 +12,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - public abstract class ToXyzw + public abstract class ToRgba32Bytes where TPixel : struct, IPixel { private IMemoryOwner source; @@ -39,8 +39,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark(Baseline = true)] - public void PerElement() + //[Benchmark] + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] + [Benchmark(Baseline = true)] public void CommonBulk() => new PixelOperations().ToRgba32Bytes( this.configuration, @@ -75,11 +75,15 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.Count); } - public class ToXyzw_Rgba32 : ToXyzw + public class ToRgba32Bytes_FromRgba32 : ToRgba32Bytes + { + } + + public class ToRgba32Bytes_FromArgb32 : ToRgba32Bytes { } - public class ToXyzw_Argb32 : ToXyzw + public class ToRgba32Bytes_FromBgra32 : ToRgba32Bytes { } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 897badd9f2..70de8f4e27 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -6,8 +6,6 @@ using System.Buffers; using System; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; @@ -48,7 +46,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } //[Benchmark] - public void PerElement() + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); @@ -69,169 +67,4 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.GetSpan()); } } - - [Config(typeof(Config.ShortClr))] - public class ToVector4_Bgra32 : ToVector4 - { - [Benchmark(Baseline = true)] - public void PixelOperations_Base() - { - new PixelOperations().ToVector4( - this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); - } - } - - [Config(typeof(Config.ShortClr))] - public class ToVector4_Rgba32 : ToVector4 - { - [Benchmark] - public void FallbackIntrinsics128() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - - [Benchmark] - public void PixelOperations_Base() - { - new PixelOperations().ToVector4( - this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); - } - - [Benchmark(Baseline = true)] - public void BasicIntrinsics256() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - - [Benchmark] - public void ExtendedIntrinsics() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); - } - - //[Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - int n = dFloats.Length / Vector.Count; - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); - ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); - - for (int i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); - d = w0; - Unsafe.Add(ref d, 1) = w1; - Unsafe.Add(ref d, 2) = w2; - Unsafe.Add(ref d, 3) = w3; - } - - n = dFloats.Length / Vector.Count; - var scale = new Vector(1f / 255f); - - for (int i = 0; i < n; i++) - { - ref Vector dRef = ref Unsafe.Add(ref destBase, i); - - Vector du = Vector.AsVectorInt32(dRef); - Vector v = Vector.ConvertToSingle(du); - v *= scale; - - dRef = v; - } - } - - //[Benchmark] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - int n = dFloats.Length / Vector.Count; - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); - var scale = new Vector(1f / 255f); - - for (int i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - Vector f0 = ConvertToNormalizedSingle(w0, scale); - Vector f1 = ConvertToNormalizedSingle(w1, scale); - Vector f2 = ConvertToNormalizedSingle(w2, scale); - Vector f3 = ConvertToNormalizedSingle(w3, scale); - - ref Vector d = ref Unsafe.Add(ref destBase, i * 4); - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) - { - Vector vi = Vector.AsVectorInt32(u); - Vector v = Vector.ConvertToSingle(vi); - v *= scale; - return v; - } - - // RESULTS (2018 October): - // - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| - // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | - // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | - // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | - // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! - // | | | | | | | | | | - // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | - // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | - // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | - // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | - // | | | | | | | | | | - // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | - // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! - // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( - // | | | | | | | | | | - // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | - // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! - // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | - // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! - } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs new file mode 100644 index 0000000000..028bfe46f8 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs @@ -0,0 +1,20 @@ +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + [Config(typeof(Config.ShortClr))] + public class ToVector4_Bgra32 : ToVector4 + { + [Benchmark(Baseline = true)] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs new file mode 100644 index 0000000000..ab05a14073 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs @@ -0,0 +1,164 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + [Config(typeof(Config.ShortClr))] + public class ToVector4_Rgba32 : ToVector4 + { + [Benchmark] + public void FallbackIntrinsics128() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + + [Benchmark(Baseline = true)] + public void BasicIntrinsics256() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark] + public void ExtendedIntrinsics() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + + n = dFloats.Length / Vector.Count; + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector dRef = ref Unsafe.Add(ref destBase, i); + + Vector du = Vector.AsVectorInt32(dRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + dRef = v; + } + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = ConvertToNormalizedSingle(w0, scale); + Vector f1 = ConvertToNormalizedSingle(w1, scale); + Vector f2 = ConvertToNormalizedSingle(w2, scale); + Vector f3 = ConvertToNormalizedSingle(w3, scale); + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; + } + + // RESULTS (2018 October): + // + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | + // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs index 9cf16ea196..a8fea68661 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -12,7 +12,7 @@ using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { //[MonoJob] - [RyuJitX64Job] + //[RyuJitX64Job] public class PixelConversion_Rgba32_To_Bgra32 { private Rgba32[] source; @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < this.Count; i++) { - Rgba32 s = Unsafe.Add(ref sBase, i); + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); Unsafe.Add(ref dBase, i).FromRgba32(s); } } @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion for (int i = 0; i < source.Length; i++) { - Rgba32 s = Unsafe.Add(ref sBase, i); + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); Unsafe.Add(ref dBase, i).FromRgba32(s); } } @@ -379,14 +379,14 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion // RESULTS: - // Method | Count | Mean | Error | StdDev | Scaled | - // -------------------- |------ |----------:|----------:|----------:|-------:| - // Default | 64 | 106.84 ns | 0.4042 ns | 0.3583 ns | 1.00 | - // Default_Generic | 64 | 113.11 ns | 0.6998 ns | 0.6203 ns | 1.06 | - // Default_Group2 | 64 | 86.81 ns | 0.4976 ns | 0.4654 ns | 0.81 | - // Default_Group4 | 64 | 83.53 ns | 1.3826 ns | 1.2933 ns | 0.78 | - // BitOps | 64 | 54.23 ns | 0.1920 ns | 0.1796 ns | 0.51 | - // Bitops_Tuple | 64 | 73.45 ns | 0.5475 ns | 0.4853 ns | 0.69 | - // BitOps_GroupAsULong | 64 | 64.28 ns | 0.4046 ns | 0.3785 ns | 0.60 | + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // -------------------- |------ |---------:|----------:|----------:|-------:|---------:| + // Default | 64 | 82.67 ns | 0.6737 ns | 0.5625 ns | 1.00 | 0.00 | + // Default_Generic | 64 | 88.73 ns | 1.7959 ns | 1.7638 ns | 1.07 | 0.02 | + // Default_Group2 | 64 | 91.03 ns | 1.5237 ns | 1.3508 ns | 1.10 | 0.02 | + // Default_Group4 | 64 | 86.62 ns | 1.5737 ns | 1.4720 ns | 1.05 | 0.02 | + // BitOps | 64 | 57.45 ns | 0.6067 ns | 0.5066 ns | 0.69 | 0.01 | + // Bitops_Tuple | 64 | 75.47 ns | 1.1824 ns | 1.1060 ns | 0.91 | 0.01 | + // BitOps_GroupAsULong | 64 | 65.42 ns | 0.7157 ns | 0.6695 ns | 0.79 | 0.01 | } } \ No newline at end of file From 9fa08b22574dbb0cfb041d72b0de49758e899cfd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 15:18:40 +0200 Subject: [PATCH 091/238] Vector4ConversionThreshold --- .../PixelFormats/PixelOperations{TPixel}.cs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index c3d8e23b91..668b2d0310 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -17,6 +17,12 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations where TPixel : struct, IPixel { + /// + /// It's not worth to bother the transitive pixel conversion method below this limit. + /// The value depends on the actual gain brought by the SIMD characteristics of the executing CPU and JIT. + /// + private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); + /// /// Gets the global instance for the pixel type /// @@ -183,7 +189,7 @@ namespace SixLabors.ImageSharp.PixelFormats int count = sourcePixels.Length; // Not worth for small buffers: - if (count < 128) + if (count < Vector4ConversionThreshold) { ToVector4DefaultImpl(sourcePixels, destVectors); return; @@ -218,7 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats int count = sourceVectors.Length; // Not worth for small buffers: - if (count < 128) + if (count < Vector4ConversionThreshold) { FromVector4DefaultImpl(sourceVectors, destPixels); return; @@ -263,5 +269,15 @@ namespace SixLabors.ImageSharp.PixelFormats dp = sp.ToVector4(); } } + + private static int CalculateVector4ConversionThreshold() + { + if (!Vector.IsHardwareAccelerated) + { + return int.MaxValue; + } + + return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128; + } } } \ No newline at end of file From 5a1cd3ade47a999f2711e2abe44f42d04e0405d6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 15:51:53 +0200 Subject: [PATCH 092/238] avoid allocation in RunRgba32CompatibleToVector4Conversion --- .../PixelFormats/PixelOperations{TPixel}.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 668b2d0310..9238e1b478 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -171,6 +171,8 @@ namespace SixLabors.ImageSharp.PixelFormats } } + // TODO: The Vector4 helpers should be moved to a utility class. + /// /// Provides an efficient default implementation for and /// which is applicable for -compatible pixel types where @@ -195,15 +197,19 @@ namespace SixLabors.ImageSharp.PixelFormats return; } - using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) - { - Span tempSpan = tempBuffer.Memory.Span; - this.ToRgba32(configuration, sourcePixels, tempSpan); + // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: + int countWithoutLastItem = count - 1; + ReadOnlySpan reducedSource = sourcePixels.Slice(0, countWithoutLastItem); + Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); + this.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); - SimdUtils.BulkConvertByteToNormalizedFloat( - MemoryMarshal.Cast(tempSpan), - MemoryMarshal.Cast(destVectors)); - } + // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers, + // but we are always reading/writing at different positions: + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(lastQuarterOfDestBuffer), + MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem))); + + destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); } /// @@ -230,6 +236,8 @@ namespace SixLabors.ImageSharp.PixelFormats return; } + // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, + // so let's allocate a temporary buffer as usually: using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) { Span tempSpan = tempBuffer.Memory.Span; From 31369c7435dae33a9578e991208bcfb480c2ecdc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 16:35:02 +0200 Subject: [PATCH 093/238] refactor Vector4 implementation code from PixelOperation to Vector4Converters --- .../Argb32.PixelOperations.Generated.cs | 9 +- .../Bgr24.PixelOperations.Generated.cs | 9 +- .../Bgra32.PixelOperations.Generated.cs | 9 +- .../Gray16.PixelOperations.Generated.cs | 1 + .../Gray8.PixelOperations.Generated.cs | 1 + .../Rgb24.PixelOperations.Generated.cs | 9 +- .../Rgb48.PixelOperations.Generated.cs | 1 + .../Rgba32.PixelOperations.Generated.cs | 1 + .../Rgba64.PixelOperations.Generated.cs | 1 + .../Generated/_Common.ttinclude | 9 +- .../PixelFormats/PixelOperations{TPixel}.cs | 147 +---------------- .../{ => Utils}/PixelConverter.cs | 3 +- .../{ => Utils}/PixelExtensions.cs | 2 +- .../Utils/Vector4Converters.Default.cs | 89 ++++++++++ .../Utils/Vector4Converters.RgbaCompatible.cs | 154 ++++++++++++++++++ .../Color/Bulk/ToVector4_Bgra32.cs | 21 +++ .../PixelConversion_ConvertFromRgba32.cs | 1 + .../PixelFormats/PixelConverterTests.cs | 1 + 18 files changed, 302 insertions(+), 166 deletions(-) rename src/ImageSharp/PixelFormats/{ => Utils}/PixelConverter.cs (98%) rename src/ImageSharp/PixelFormats/{ => Utils}/PixelExtensions.cs (93%) create mode 100644 src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs create mode 100644 src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index e6b8922e9d..6449351cca 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -45,25 +46,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 9b1740013d..9232cf4549 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -45,25 +46,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 37d6b72d71..4f56b75c5a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -45,25 +46,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index 638db1d0d8..81882185d1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index 6bf0693c2c..f6678a4f87 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index 6ff87eb385..aae8b2f637 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -45,25 +46,25 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 9b4584d767..c828053a4c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index 8e15ca1f4d..9c29bd0445 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index caaba78094..db9cb84bec 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -3,6 +3,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index 4501f4972e..cc8cb0e2fc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -8,6 +8,7 @@ // +using SixLabors.ImageSharp.PixelFormats.Utils; using System; using System.Buffers; using System.Numerics; @@ -114,25 +115,25 @@ using System.Runtime.InteropServices; /// internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); } /// internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); } /// internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) { - this.RunRgba32CompatibleFromVector4Conversion(configuration, sourceVectors, destPixels); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); } /// internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) { - this.RunRgba32CompatibleToVector4Conversion(configuration, sourcePixels, destVectors); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); } <#+ diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 9238e1b478..f4eb19be33 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -17,12 +17,6 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations where TPixel : struct, IPixel { - /// - /// It's not worth to bother the transitive pixel conversion method below this limit. - /// The value depends on the actual gain brought by the SIMD characteristics of the executing CPU and JIT. - /// - private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); - /// /// Gets the global instance for the pixel type /// @@ -42,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - FromVector4DefaultImpl(sourceVectors, destPixels); + Utils.Vector4Converters.Default.DangerousFromVector4(sourceVectors, destPixels); } /// @@ -59,7 +53,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - ToVector4DefaultImpl(sourcePixels, destVectors); + Utils.Vector4Converters.Default.DangerousToVector4(sourcePixels, destVectors); } /// @@ -76,15 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - - for (int i = 0; i < sourceVectors.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromScaledVector4(sp); - } + Utils.Vector4Converters.Default.DangerousFromScaledVector4(sourceVectors, destinationColors); } /// @@ -101,15 +87,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - - for (int i = 0; i < sourceColors.Length; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToScaledVector4(); - } + Utils.Vector4Converters.Default.DangerousToScaledVector4(sourceColors, destinationVectors); } /// @@ -170,122 +148,5 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromScaledVector4(sp.ToScaledVector4()); } } - - // TODO: The Vector4 helpers should be moved to a utility class. - - /// - /// Provides an efficient default implementation for and - /// which is applicable for -compatible pixel types where - /// returns the same scaled result as . - /// The method is works by internally converting to a therefore it's not applicable for that type! - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal void RunRgba32CompatibleToVector4Conversion( - Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors) - { - Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - - int count = sourcePixels.Length; - - // Not worth for small buffers: - if (count < Vector4ConversionThreshold) - { - ToVector4DefaultImpl(sourcePixels, destVectors); - return; - } - - // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: - int countWithoutLastItem = count - 1; - ReadOnlySpan reducedSource = sourcePixels.Slice(0, countWithoutLastItem); - Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); - this.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); - - // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers, - // but we are always reading/writing at different positions: - SimdUtils.BulkConvertByteToNormalizedFloat( - MemoryMarshal.Cast(lastQuarterOfDestBuffer), - MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem))); - - destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); - } - - /// - /// Provides an efficient default implementation for and - /// which is applicable for -compatible pixel types where - /// returns the same scaled result as . - /// The method is works by internally converting to a therefore it's not applicable for that type! - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal void RunRgba32CompatibleFromVector4Conversion( - Configuration configuration, - ReadOnlySpan sourceVectors, - Span destPixels) - { - Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - - int count = sourceVectors.Length; - - // Not worth for small buffers: - if (count < Vector4ConversionThreshold) - { - FromVector4DefaultImpl(sourceVectors, destPixels); - return; - } - - // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, - // so let's allocate a temporary buffer as usually: - using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) - { - Span tempSpan = tempBuffer.Memory.Span; - - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( - MemoryMarshal.Cast(sourceVectors), - MemoryMarshal.Cast(tempSpan)); - - this.FromRgba32(configuration, tempSpan, destPixels); - } - } - - [MethodImpl(InliningOptions.ShortMethod)] - private static void FromVector4DefaultImpl(ReadOnlySpan sourceVectors, Span destPixels) - { - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < sourceVectors.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromVector4(sp); - } - } - - [MethodImpl(InliningOptions.ShortMethod)] - private static void ToVector4DefaultImpl(ReadOnlySpan sourcePixels, Span destVectors) - { - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); - - for (int i = 0; i < sourcePixels.Length; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } - } - - private static int CalculateVector4ConversionThreshold() - { - if (!Vector.IsHardwareAccelerated) - { - return int.MaxValue; - } - - return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs similarity index 98% rename from src/ImageSharp/PixelFormats/PixelConverter.cs rename to src/ImageSharp/PixelFormats/Utils/PixelConverter.cs index 8fde490fda..2336dbee74 100644 --- a/src/ImageSharp/PixelFormats/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -1,11 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Buffers.Binary; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.PixelFormats +namespace SixLabors.ImageSharp.PixelFormats.Utils { /// /// Contains optimized implementations for conversion between pixel formats. diff --git a/src/ImageSharp/PixelFormats/PixelExtensions.cs b/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs similarity index 93% rename from src/ImageSharp/PixelFormats/PixelExtensions.cs rename to src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs index 175696ab63..2284b8fc27 100644 --- a/src/ImageSharp/PixelFormats/PixelExtensions.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -namespace SixLabors.ImageSharp.PixelFormats +namespace SixLabors.ImageSharp.PixelFormats.Utils { /// /// Low-performance extension methods to help conversion syntax, suitable for testing purposes. diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs new file mode 100644 index 0000000000..139dbfa10f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs @@ -0,0 +1,89 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Helper class for (bulk) conversion of buffers to/from other buffer types. + /// + internal static partial class Vector4Converters + { + /// + /// Provides default implementations for batched to/from conversion. + /// WARNING: The methods are operating without bounds checking and input validation! + /// Input validation is the responsibility of the caller! + /// + public static class Default + { + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromVector4( + ReadOnlySpan sourceVectors, + Span destPixels) + where TPixel : struct, IPixel + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToVector4( + ReadOnlySpan sourcePixels, + Span destVectors) + where TPixel : struct, IPixel + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromScaledVector4( + ReadOnlySpan sourceVectors, + Span destinationColors) + where TPixel : struct, IPixel + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromScaledVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToScaledVector4( + ReadOnlySpan sourceColors, + Span destinationVectors) + where TPixel : struct, IPixel + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + + for (int i = 0; i < sourceColors.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToScaledVector4(); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs new file mode 100644 index 0000000000..7c57fe4fbd --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -0,0 +1,154 @@ +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Contains + /// + internal static partial class Vector4Converters + { + /// + /// Provides efficient implementations for batched to/from conversion. + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + public static class RgbaCompatible + { + /// + /// It's not worth to bother the transitive pixel conversion method below this limit. + /// The value depends on the actual gain brought by the SIMD characteristics of the executing CPU and JIT. + /// + private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); + + /// + /// Provides an efficient default implementation for + /// and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ToVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourcePixels, + Span destVectors, + bool scaled) + where TPixel : struct, IPixel + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + int count = sourcePixels.Length; + + // Not worth for small buffers: + if (count < Vector4ConversionThreshold) + { + ToVector4Fallback(sourcePixels, destVectors, scaled); + + return; + } + + // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: + int countWithoutLastItem = count - 1; + ReadOnlySpan reducedSource = sourcePixels.Slice(0, countWithoutLastItem); + Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); + pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); + + // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers, + // but we are always reading/writing at different positions: + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(lastQuarterOfDestBuffer), + MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem))); + + destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); + } + + /// + /// Provides an efficient default implementation for + /// and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void FromVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourceVectors, + Span destPixels, + bool scaled) + where TPixel : struct, IPixel + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + int count = sourceVectors.Length; + + // Not worth for small buffers: + if (count < Vector4ConversionThreshold) + { + FromVector4Fallback(sourceVectors, destPixels, scaled); + + return; + } + + // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, + // so let's allocate a temporary buffer as usually: + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) + { + Span tempSpan = tempBuffer.Memory.Span; + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(tempSpan)); + + pixelOperations.FromRgba32(configuration, tempSpan, destPixels); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ToVector4Fallback(ReadOnlySpan sourcePixels, Span destVectors, bool scaled) + where TPixel : struct, IPixel + { + if (scaled) + { + Default.DangerousToScaledVector4(sourcePixels, destVectors); + } + else + { + Default.DangerousToVector4(sourcePixels, destVectors); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void FromVector4Fallback(ReadOnlySpan sourceVectors, Span destPixels, bool scaled) + where TPixel : struct, IPixel + { + if (scaled) + { + Default.DangerousFromScaledVector4(sourceVectors, destPixels); + } + else + { + Default.DangerousFromVector4(sourceVectors, destPixels); + } + } + + private static int CalculateVector4ConversionThreshold() + { + if (!Vector.IsHardwareAccelerated) + { + return int.MaxValue; + } + + return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs index 028bfe46f8..39702d5253 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs @@ -16,5 +16,26 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.source.GetSpan(), this.destination.GetSpan()); } + + // RESULTS: + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |-----------:|------------:|-----------:|-------:|---------:|-------:|----------:| + // PixelOperations_Base | Clr | 64 | 339.9 ns | 138.30 ns | 7.8144 ns | 1.00 | 0.00 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 338.1 ns | 13.30 ns | 0.7515 ns | 0.99 | 0.02 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 64 | 245.6 ns | 29.05 ns | 1.6413 ns | 1.00 | 0.00 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 257.1 ns | 37.89 ns | 2.1407 ns | 1.05 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Clr | 256 | 972.7 ns | 61.98 ns | 3.5020 ns | 1.00 | 0.00 | 0.0057 | 24 B | + // PixelOperations_Specialized | Clr | 256 | 882.9 ns | 126.21 ns | 7.1312 ns | 0.91 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 256 | 910.0 ns | 90.87 ns | 5.1346 ns | 1.00 | 0.00 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 256 | 448.4 ns | 15.77 ns | 0.8910 ns | 0.49 | 0.00 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Clr | 2048 | 6,951.8 ns | 1,299.01 ns | 73.3963 ns | 1.00 | 0.00 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 5,852.3 ns | 630.56 ns | 35.6279 ns | 0.84 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 2048 | 6,937.5 ns | 1,692.19 ns | 95.6121 ns | 1.00 | 0.00 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,994.5 ns | 1,126.65 ns | 63.6578 ns | 0.43 | 0.01 | - | 0 B | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 424020e2f2..9f1b2721b4 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats.Utils; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs index 9b32f7aeee..c539e9dcf0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -1,4 +1,5 @@ using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats.Utils; using Xunit; From 09de1b1cde7a43d35a3759699539b31a27349b67 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 19:43:00 +0200 Subject: [PATCH 094/238] better docs, drop PixelExtensions, fix tests --- .../PixelFormats/Utils/PixelConverter.cs | 12 +++++----- .../PixelFormats/Utils/PixelExtensions.cs | 22 ------------------- .../Drawing/FillLinearGradientBrushTests.cs | 4 +++- .../PixelFormats/Alpha8Tests.cs | 3 ++- .../PixelFormats/Gray16Tests.cs | 3 ++- .../PixelFormats/Gray8Tests.cs | 5 +++-- .../PixelFormats/Rgb24Tests.cs | 3 ++- .../PixelFormats/Rgb48Tests.cs | 3 ++- .../PixelFormats/Rgba1010102Tests.cs | 3 ++- .../PixelFormats/Rgba64Tests.cs | 2 +- .../PixelFormats/Short2Tests.cs | 4 ++-- .../PixelFormats/Short4Tests.cs | 12 ++++++---- .../PixelFormats/UnPackedPixelTests.cs | 6 +++-- .../Quantization/QuantizedImageTests.cs | 3 ++- .../TestUtilities/TestUtils.cs | 7 ++++-- .../Tests/TestImageProviderTests.cs | 3 ++- 16 files changed, 47 insertions(+), 48 deletions(-) delete mode 100644 src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs diff --git a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs index 2336dbee74..55a94fc81e 100644 --- a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -12,7 +12,9 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils /// /// Implementations are based on ideas in: /// https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs#L84 - /// The JIT should be able to detect and optimize ROL and ROR patterns. + /// The JIT can detect and optimize rotation idioms ROTL (Rotate Left) + /// and ROTR (Rotate Right) emitting efficient CPU instructions: + /// https://github.com/dotnet/coreclr/pull/1830 /// internal static class PixelConverter { @@ -25,7 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils public static uint ToArgb32(uint packedRgba) { // packedRgba = [aa bb gg rr] - // ROL(8, packedRgba) = [bb gg rr aa] + // ROTL(8, packedRgba) = [bb gg rr aa] return (packedRgba << 8) | (packedRgba >> 24); } @@ -38,7 +40,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils // packedRgba = [aa bb gg rr] // tmp1 = [aa 00 gg 00] // tmp2 = [00 bb 00 rr] - // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp3=ROTL(16, tmp2) = [00 rr 00 bb] // tmp1 + tmp3 = [aa rr gg bb] uint tmp1 = packedRgba & 0xFF00FF00; uint tmp2 = packedRgba & 0x00FF00FF; @@ -56,7 +58,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils public static uint ToRgba32(uint packedArgb) { // packedArgb = [bb gg rr aa] - // ROR(8, packedArgb) = [aa bb gg rr] + // ROTR(8, packedArgb) = [aa bb gg rr] return (packedArgb >> 8) | (packedArgb << 24); } @@ -94,7 +96,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils // packedRgba = [aa rr gg bb] // tmp1 = [aa 00 gg 00] // tmp2 = [00 rr 00 bb] - // tmp3=ROL(16, tmp2) = [00 bb 00 rr] + // tmp3=ROTL(16, tmp2) = [00 bb 00 rr] // tmp1 + tmp3 = [aa bb gg rr] uint tmp1 = packedBgra & 0xFF00FF00; uint tmp2 = packedBgra & 0x00FF00FF; diff --git a/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs b/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs deleted file mode 100644 index 2284b8fc27..0000000000 --- a/src/ImageSharp/PixelFormats/Utils/PixelExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats.Utils -{ - /// - /// Low-performance extension methods to help conversion syntax, suitable for testing purposes. - /// - internal static class PixelExtensions - { - /// - /// Returns the result of as a new instance. - /// - public static Rgba32 ToRgba32(this TPixel pixel) - where TPixel : struct, IPixel - { - Rgba32 result = default; - pixel.ToRgba32(ref result); - return result; - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index 9121649f48..556ec9c9ca 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -328,7 +328,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing TPixel color = colors[stopColorCodes[i % colors.Length]]; float position = stopPositions[i]; colorStops[i] = new ColorStop(position, color); - coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color.ToRgba32().ToHex(), position); + Rgba32 rgba = default; + color.ToRgba32(ref rgba); + coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", rgba.ToHex(), position); } FormattableString variant = $"({startX},{startY})_TO_({endX},{endY})__[{coloringVariant}]"; diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 148b928fac..8f68c9d03f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -90,7 +90,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var input = new Alpha8(128); var expected = new Rgba32(0, 0, 0, 128); - var actual = input.ToRgba32(); + Rgba32 actual = default; + input.ToRgba32(ref actual); Assert.Equal(expected, actual); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs index 220ca2899a..cb19c031d0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -117,7 +117,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var gray = new Gray16(input); // Act - var actual = gray.ToRgba32(); + Rgba32 actual = default; + gray.ToRgba32(ref actual); // Assert Assert.Equal(expected, actual.R); diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index 988002c099..6a7b20cbed 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -115,10 +115,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var gray = new Gray8(input); // Act - var actual = gray.ToRgba32(); + Rgba32 actual = default; + gray.ToRgba32(ref actual); // Assert - Assert.Equal(input, actual.R); + Assert.Equal(input, actual.R); Assert.Equal(input, actual.G); Assert.Equal(input, actual.B); Assert.Equal(byte.MaxValue, actual.A); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index a60509146d..92e8d302d4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -104,7 +104,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void ToRgba32() { var rgb = new Rgb24(1, 2, 3); - var rgba = rgb.ToRgba32(); + Rgba32 rgba = default; + rgb.ToRgba32(ref rgba); Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index a7f0e5edfc..d30e498609 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -52,7 +52,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 76, 255); // act - var actual = rgba48.ToRgba32(); + Rgba32 actual = default; + rgba48.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index ad7df30769..a897dd4cdb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -79,7 +79,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(25, 0, 128, 0); // act - var actual = rgba.ToRgba32(); + Rgba32 actual = default; + rgba.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 564c26b8b1..3e5d7a56ed 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 76, 115); // act - actual = rgba64.ToRgba32(); + rgba64.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 725e1a0d14..c9a3b33c9a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(128, 127, 0, 255); // act - actual = short2.ToRgba32(); + short2.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short2.FromRgba32(expected); - actual = short2.ToRgba32(); + short2.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index b19917f34a..247342a053 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(172, 177, 243, 128); // act - actual = shortValue.ToRgba32(); + shortValue.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.FromRgba32(expected); - actual = short4.ToRgba32(); + short4.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); @@ -124,7 +124,9 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.FromBgra32(expected); - actual.FromRgba32(short4.ToRgba32()); + Rgba32 temp = default; + short4.ToRgba32(ref temp); + actual.FromRgba32(temp); // assert Assert.Equal(expected, actual); @@ -140,7 +142,9 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act short4.FromArgb32(expected); - actual.FromRgba32(short4.ToRgba32()); + Rgba32 temp = default; + short4.ToRgba32(ref temp); + actual.FromRgba32(temp); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 29c97ce35f..bd8c647421 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -84,8 +84,10 @@ namespace SixLabors.ImageSharp.Tests.Colors var color = new Rgba32(24, 48, 96, 192); var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - var rgba = color.ToRgba32(); - var rgbaVector = colorVector.ToRgba32(); + Rgba32 rgba = default; + Rgba32 rgbaVector = default; + color.ToRgba32(ref rgba); + colorVector.ToRgba32(ref rgbaVector); Assert.Equal(rgba, rgbaVector); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index fa855aef77..577dc83c53 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -106,9 +106,10 @@ namespace SixLabors.ImageSharp.Tests { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; + Rgba32 trans = default; for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - var trans = quantized.Palette[i].ToRgba32(); + quantized.Palette[i].ToRgba32(ref trans); if (trans.Equals(default)) { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index e6a5ffc84b..d7755ff7a4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -80,8 +80,11 @@ namespace SixLabors.ImageSharp.Tests } else { - rgb1 = ca.ToRgba32().Rgb; - rgb2 = cb.ToRgba32().Rgb; + Rgba32 rgba = default; + ca.ToRgba32(ref rgba); + rgb1 = rgba.Rgb; + cb.ToRgba32(ref rgba); + rgb2 = rgba.Rgb; if (!rgb1.Equals(rgb2)) { diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 1d284af15e..a8140e39d4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -275,11 +275,12 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(20, img.Height); Buffer2D pixels = img.GetRootFramePixelBuffer(); + Rgba32 rgba = default; for (int y = 0; y < pixels.Height; y++) { for (int x = 0; x < pixels.Width; x++) { - var rgba = pixels[x, y].ToRgba32(); + pixels[x, y].ToRgba32(ref rgba); Assert.Equal(255, rgba.R); Assert.Equal(100, rgba.G); From 16018e5c6a44c3038d70797469e2c8eca43e2f0a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 20:04:19 +0200 Subject: [PATCH 095/238] refactor PixelOperationsTests --- tests/ImageSharp.Tests/ConfigurationTests.cs | 1 + .../ImageSharp.Tests/GraphicsOptionsTests.cs | 21 + ...elOperationsTests.Argb32OperationsTests.cs | 22 + ...xelOperationsTests.Bgr24OperationsTests.cs | 21 + ...elOperationsTests.Bgra32OperationsTests.cs | 21 + ...elOperationsTests.Gray16OperationsTests.cs | 111 +++++ ...xelOperationsTests.Gray8OperationsTests.cs | 111 +++++ ...xelOperationsTests.Rgb48OperationsTests.cs | 21 + ...elOperationsTests.Rgba32OperationsTests.cs | 43 ++ ...elOperationsTests.Rgba64OperationsTests.cs | 21 + ...erationsTests.RgbaVectorOperationsTests.cs | 21 + .../PixelOperationsTests.cs | 394 +++--------------- 12 files changed, 476 insertions(+), 332 deletions(-) create mode 100644 tests/ImageSharp.Tests/GraphicsOptionsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs create mode 100644 tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs rename tests/ImageSharp.Tests/PixelFormats/{ => PixelOperations}/PixelOperationsTests.cs (63%) diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 963d674466..208387e6d1 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -6,6 +6,7 @@ using System.Linq; using Moq; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.IO; + using Xunit; // ReSharper disable InconsistentNaming diff --git a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs new file mode 100644 index 0000000000..6ff38626d6 --- /dev/null +++ b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public class GraphicsOptionsTests + { + [Fact] + public void IsOpaqueColor() + { + Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs new file mode 100644 index 0000000000..875ba0cba4 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs @@ -0,0 +1,22 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Argb32OperationsTests : PixelOperationsTests + { + + public Argb32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs new file mode 100644 index 0000000000..879712a3e5 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Bgr24OperationsTests : PixelOperationsTests + { + public Bgr24OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs new file mode 100644 index 0000000000..963a9dae6d --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Bgra32OperationsTests : PixelOperationsTests + { + public Bgra32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs new file mode 100644 index 0000000000..1afa65240a --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs @@ -0,0 +1,111 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Gray16OperationsTests : PixelOperationsTests + { + public Gray16OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + expected[i].FromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs new file mode 100644 index 0000000000..4112d201b5 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs @@ -0,0 +1,111 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Gray8OperationsTests : PixelOperationsTests + { + public Gray8OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + expected[i].FromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs new file mode 100644 index 0000000000..68b67fce27 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgb48OperationsTests : PixelOperationsTests + { + public Rgb48OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs new file mode 100644 index 0000000000..38cc978930 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs @@ -0,0 +1,43 @@ +using System.Buffers; +using System.Numerics; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgba32OperationsTests : PixelOperationsTests + { + public Rgba32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Fact(Skip = SkipProfilingBenchmarks)] + public void Benchmark_ToVector4() + { + const int times = 200000; + const int count = 1024; + + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) + { + this.Measure( + times, + () => PixelOperations.Instance.ToVector4( + this.Configuration, + source.GetSpan(), + dest.GetSpan())); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs new file mode 100644 index 0000000000..47738ac609 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgba64OperationsTests : PixelOperationsTests + { + public Rgba64OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs new file mode 100644 index 0000000000..7272dfb781 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs @@ -0,0 +1,21 @@ +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class RgbaVectorOperationsTests : PixelOperationsTests + { + public RgbaVectorOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs similarity index 63% rename from tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs rename to tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index e66ca9a714..d9845e4741 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -6,335 +6,65 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; + using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.PixelFormats +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { - public class PixelOperationsTests + public partial class PixelOperationsTests { - public const string SkipProfilingBenchmarks = -#if true - "Profiling benchmark - enable manually!"; -#else - null; -#endif - - public class Argb32OperationsTests : PixelOperationsTests - { - - public Argb32OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Bgr24OperationsTests : PixelOperationsTests - { - public Bgr24OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Bgra32OperationsTests : PixelOperationsTests - { - public Bgra32OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Gray8OperationsTests : PixelOperationsTests - { - public Gray8OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray8Bytes(int count) - { - byte[] source = CreateByteTestData(count); - var expected = new Gray8[count]; - - for (int i = 0; i < count; i++) - { - expected[i].FromGray8(new Gray8(source[i])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray8Bytes(int count) - { - Gray8[] source = CreatePixelTestData(count); - byte[] expected = new byte[count]; - var gray = default(Gray8); - - for (int i = 0; i < count; i++) - { - gray.FromScaledVector4(source[i].ToScaledVector4()); - expected[i] = gray.PackedValue; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray16Bytes(int count) - { - byte[] source = CreateByteTestData(count * 2); - Span sourceSpan = source.AsSpan(); - var expected = new Gray8[count]; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray16Bytes(int count) - { - Gray8[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 2]; - Gray16 gray = default; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - gray.FromScaledVector4(source[i].ToScaledVector4()); - OctetBytes bytes = Unsafe.As(ref gray); - expected[i2] = bytes[0]; - expected[i2 + 1] = bytes[1]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - } - - public class Gray16OperationsTests : PixelOperationsTests - { - public Gray16OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray8Bytes(int count) - { - byte[] source = CreateByteTestData(count); - var expected = new Gray16[count]; - - for (int i = 0; i < count; i++) - { - expected[i].FromGray8(new Gray8(source[i])); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray8Bytes(int count) - { - Gray16[] source = CreatePixelTestData(count); - byte[] expected = new byte[count]; - var gray = default(Gray8); - - for (int i = 0; i < count; i++) - { - gray.FromScaledVector4(source[i].ToScaledVector4()); - expected[i] = gray.PackedValue; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void FromGray16Bytes(int count) - { - byte[] source = CreateByteTestData(count * 2); - Span sourceSpan = source.AsSpan(); - var expected = new Gray16[count]; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); - } - - TestOperation( - source, - expected, - (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void ToGray16Bytes(int count) - { - Gray16[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 2]; - Gray16 gray = default; - - for (int i = 0; i < count; i++) - { - int i2 = i * 2; - gray.FromScaledVector4(source[i].ToScaledVector4()); - OctetBytes bytes = Unsafe.As(ref gray); - expected[i2] = bytes[0]; - expected[i2 + 1] = bytes[1]; - } - - TestOperation( - source, - expected, - (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) - ); - } - } - - public class Rgba32OperationsTests : PixelOperationsTests - { - public Rgba32OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - - [Fact(Skip = SkipProfilingBenchmarks)] - public void Benchmark_ToVector4() - { - const int times = 200000; - const int count = 1024; - - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) - using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) - { - this.Measure( - times, - () => PixelOperations.Instance.ToVector4( - this.Configuration, - source.GetSpan(), - dest.GetSpan())); - } - } - } - - public class Rgb48OperationsTests : PixelOperationsTests - { - public Rgb48OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class Rgba64OperationsTests : PixelOperationsTests - { - public Rgba64OperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - - public class RgbaVectorOperationsTests : PixelOperationsTests - { - public RgbaVectorOperationsTests(ITestOutputHelper output) - : base(output) - { - } - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - } - [Theory] [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider _) - where TPixel : struct, IPixel => Assert.NotNull(PixelOperations.Instance); - - [Fact] - public void IsOpaqueColor() - { - Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); - } + public void GetGlobalInstance(TestImageProvider _) + where T : struct, IPixel => Assert.NotNull(PixelOperations.Instance); } public abstract class PixelOperationsTests : MeasureFixture where TPixel : struct, IPixel { + public const string SkipProfilingBenchmarks = +#if true + "Profiling benchmark - enable manually!"; +#else + null; +#endif + protected PixelOperationsTests(ITestOutputHelper output) : base(output) { } - public static TheoryData ArraySizesData => new TheoryData { 0, 1, 2, 7, 16, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 1111 }; + public static TheoryData ArraySizesData => + new TheoryData + { + 0, + 1, + 2, + 7, + 16, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520, + 521, + 522, + 523, + 524, + 525, + 526, + 527, + 528, + 1111 + }; protected Configuration Configuration => Configuration.Default; @@ -390,28 +120,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ); } - internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToVector4(); - } - return expected; - } - - internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToScaledVector4(); - } - return expected; - } - [Theory] [MemberData(nameof(ArraySizesData))] public void ToVector4(int count) @@ -769,6 +477,28 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ); } + internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToVector4(); + } + return expected; + } + + internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; + + for (int i = 0; i < expected.Length; i++) + { + expected[i] = source[i].ToScaledVector4(); + } + return expected; + } + internal static void TestOperation( TSource[] source, TDest[] expected, From 633c212bdd45e083f4c4fd2b5de38cd02b95ddd9 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 20:30:48 +0200 Subject: [PATCH 096/238] add header --- .../PixelOperationsTests.Argb32OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Bgr24OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Bgra32OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Gray16OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Gray8OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Rgb48OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Rgba32OperationsTests.cs | 5 ++++- .../PixelOperationsTests.Rgba64OperationsTests.cs | 5 ++++- .../PixelOperationsTests.RgbaVectorOperationsTests.cs | 5 ++++- 9 files changed, 36 insertions(+), 9 deletions(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs index 875ba0cba4..c881ae96ba 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs index 879712a3e5..323d3914cf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs index 963a9dae6d..1c966951fc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs index 1afa65240a..c3de335470 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs index 4112d201b5..acd6ef23ac 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs index 68b67fce27..0a28db6b0a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs index 38cc978930..1ecbaf3615 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs @@ -1,4 +1,7 @@ -using System.Buffers; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Buffers; using System.Numerics; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs index 47738ac609..6787602bb2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs index 7272dfb781..f9cc042a77 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs @@ -1,4 +1,7 @@ -using SixLabors.ImageSharp.PixelFormats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; From cf7af016bec905f2e7399c57fe638d4dc45b097c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 26 Oct 2018 20:33:25 +0200 Subject: [PATCH 097/238] fix Sandbox46 build --- tests/ImageSharp.Sandbox46/Program.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index 4d89929a03..3a3a7d31cd 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -3,6 +3,8 @@ // Licensed under the Apache License, Version 2.0. // +using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; + namespace SixLabors.ImageSharp.Sandbox46 { using System; From 013d58e3ddc79badd275d5fe6d586b148f8e8761 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Fri, 26 Oct 2018 22:58:35 +0200 Subject: [PATCH 098/238] Added missing length check that caused an ArgumentNullException (#750) --- .../Common/Extensions/EncoderExtensions.cs | 5 +++ .../Common/EncoderExtensionsTests.cs | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs diff --git a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs index 82899863c9..086dbee35a 100644 --- a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs +++ b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs @@ -20,6 +20,11 @@ namespace SixLabors.ImageSharp /// The string. public static string GetString(this Encoding encoding, ReadOnlySpan buffer) { + if (buffer.Length == 0) + { + return null; + } + fixed (byte* bytes = buffer) { return encoding.GetString(bytes, buffer.Length); diff --git a/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs new file mode 100644 index 0000000000..ec1ae65d6d --- /dev/null +++ b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Text; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Common +{ + public class EncoderExtensionsTests + { + [Fact] + public void GetString_EmptyBuffer_ReturnsNull() + { + var buffer = new ReadOnlySpan(); + + string result = Encoding.UTF8.GetString(buffer); + + Assert.Null(result); + } + + [Fact] + public void GetString_Buffer_ReturnsString() + { + var buffer = new ReadOnlySpan(new byte[] { 73, 109, 97, 103, 101, 83, 104, 97, 114, 112 }); + + string result = Encoding.UTF8.GetString(buffer); + + Assert.Equal("ImageSharp", result); + } + } +} From a2a4bcbfab0fc2dcaf29247800a8830249824736 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Fri, 26 Oct 2018 23:32:35 +0200 Subject: [PATCH 099/238] Return empty string instead of null. --- src/ImageSharp/Common/Extensions/EncoderExtensions.cs | 2 +- tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs index 086dbee35a..59c878485d 100644 --- a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs +++ b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp { if (buffer.Length == 0) { - return null; + return string.Empty; } fixed (byte* bytes = buffer) diff --git a/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs index ec1ae65d6d..e1b4fc790c 100644 --- a/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs @@ -10,13 +10,13 @@ namespace SixLabors.ImageSharp.Tests.Common public class EncoderExtensionsTests { [Fact] - public void GetString_EmptyBuffer_ReturnsNull() + public void GetString_EmptyBuffer_ReturnsEmptyString() { var buffer = new ReadOnlySpan(); string result = Encoding.UTF8.GetString(buffer); - Assert.Null(result); + Assert.Equal(string.Empty, result); } [Fact] From 25bc07427310d2f3445172b828c734677784f185 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 27 Oct 2018 00:09:33 +0200 Subject: [PATCH 100/238] imrpoved accuracy for Gray8 conversion --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- .../PixelImplementations/Gray8.cs | 15 +- .../PixelFormats/Gray8Tests.cs | 168 +++++++++++++++--- 3 files changed, 158 insertions(+), 27 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 6c52eded5f..402aa79b5f 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F)); + public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f); /// /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs index d23fda7991..b49eb2505d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs @@ -18,6 +18,11 @@ namespace SixLabors.ImageSharp.PixelFormats private static readonly Vector4 Half = new Vector4(0.5F); private const float Average = 1 / 3F; + private static readonly Vector4 Min = new Vector4(0, 0, 0, 1f); + private static readonly Vector4 Max = Vector4.One; + + private static readonly Vector4 Accumulator = new Vector4(255f * Average, 255f * Average, 255f * Average, 0.5f); + /// /// Initializes a new instance of the struct. /// @@ -64,10 +69,12 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromVector4(Vector4 vector) { - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes) * Average; - this.PackedValue = (byte)(vector.X + vector.Y + vector.Z); + vector = Vector4.Max(Min, vector); + vector = Vector4.Min(Max, vector); + + float roundedSum = Vector4.Dot(vector, Accumulator); + + this.PackedValue = (byte)roundedSum; } /// diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs index 988002c099..fcd8da0512 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -1,14 +1,42 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Diagnostics; using System.Numerics; + +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.PixelFormats; using Xunit; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.PixelFormats { public class Gray8Tests { + public static readonly TheoryData LuminanceData = new TheoryData() + { + 0, + 1, + 2, + 3, + 5, + 13, + 31, + 71, + 73, + 79, + 83, + 109, + 127, + 128, + 131, + 199, + 250, + 251, + 254, + 255 + }; + [Theory] [InlineData(0)] [InlineData(255)] @@ -34,9 +62,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Theory] - [InlineData(0)] - [InlineData(255)] - [InlineData(30)] + [MemberData(nameof(LuminanceData))] public void Gray8_ToScaledVector4(byte input) { // Arrange @@ -53,26 +79,24 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(1, actual.W); } - [Fact] - public void Gray8_FromVector4() + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_FromVector4(byte luminance) { // Arrange Gray8 gray = default; - const int expected = 128; - var vector = new Gray8(expected).ToVector4(); + var vector = new Gray8(luminance).ToVector4(); // Act gray.FromVector4(vector); byte actual = gray.PackedValue; // Assert - Assert.Equal(expected, actual); + Assert.Equal(luminance, actual); } [Theory] - [InlineData(0)] - [InlineData(255)] - [InlineData(30)] + [MemberData(nameof(LuminanceData))] public void Gray8_ToVector4(byte input) { // Arrange @@ -89,12 +113,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(1, actual.W); } - [Fact] - public void Gray8_FromRgba32() + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_FromRgba32(byte rgb) { // Arrange Gray8 gray = default; - const byte rgb = 128; byte expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb); // Act @@ -105,23 +129,123 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(expected, actual); } + [Theory] - [InlineData(0)] - [InlineData(255)] - [InlineData(30)] - public void Gray8_ToRgba32(byte input) + [MemberData(nameof(LuminanceData))] + public void Gray8_ToRgba32(byte luminance) { // Arrange - var gray = new Gray8(input); + var gray = new Gray8(luminance); // Act var actual = gray.ToRgba32(); // Assert - Assert.Equal(input, actual.R); - Assert.Equal(input, actual.G); - Assert.Equal(input, actual.B); + Assert.Equal(luminance, actual.R); + Assert.Equal(luminance, actual.G); + Assert.Equal(luminance, actual.B); Assert.Equal(byte.MaxValue, actual.A); } + + public class Rgba32Compatibility + { + // ReSharper disable once MemberHidesStaticFromOuterClass + public static readonly TheoryData LuminanceData = Gray8Tests.LuminanceData; + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_FromRgba32_IsInverseOf_ToRgba32(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Gray8 mirror = default; + mirror.FromRgba32(rgba); + + Assert.Equal(original, mirror); + } + + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Rgba32_ToGray8_IsInverseOf_Gray8_ToRgba32(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Gray8 mirror = default; + mirror.FromRgba32(rgba); + + Assert.Equal(original, mirror); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void ToVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + var gray8Vector = original.ToVector4(); + var rgbaVector = original.ToVector4(); + + Assert.Equal(gray8Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void FromVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Vector4 rgbaVector = original.ToVector4(); + + Gray8 mirror = default; + mirror.FromVector4(rgbaVector); + + Assert.Equal(original, mirror); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void ToScaledVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Vector4 gray8Vector = original.ToScaledVector4(); + Vector4 rgbaVector = original.ToScaledVector4(); + + Assert.Equal(gray8Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void FromScaledVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Vector4 rgbaVector = original.ToScaledVector4(); + + Gray8 mirror = default; + mirror.FromScaledVector4(rgbaVector); + + Assert.Equal(original, mirror); + } + } } } \ No newline at end of file From ba6ecfead5f345c3109cf2cae1a8b88f3c62a1ab Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 27 Oct 2018 11:36:01 +0100 Subject: [PATCH 101/238] Add issue reference images --- .../Formats/Jpg/JpegDecoderTests.Images.cs | 4 +++- tests/ImageSharp.Tests/TestImages.cs | 2 ++ tests/Images/External | 2 +- .../Input/Jpg/issues/issue750-exif-load.jpg | Bin 0 -> 36885 bytes .../Jpg/issues/issue750-exif-tranform.jpg | Bin 0 -> 5587341 bytes 5 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Jpg/issues/issue750-exif-load.jpg create mode 100644 tests/Images/Input/Jpg/issues/issue750-exif-tranform.jpg diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index 6bc559978c..17a0ff2632 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -26,7 +26,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, TestImages.Jpeg.Issues.InvalidEOI695, TestImages.Jpeg.Issues.ExifResizeOutOfRange696, - TestImages.Jpeg.Issues.InvalidAPP0721 + TestImages.Jpeg.Issues.InvalidAPP0721, + TestImages.Jpeg.Issues.ExifGetString750Load, + TestImages.Jpeg.Issues.ExifGetString750Transform }; public static string[] ProgressiveTestJpegs = diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 758f256345..03f8754854 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -160,6 +160,8 @@ namespace SixLabors.ImageSharp.Tests public const string OrderedInterleavedProgressive723A = "Jpg/issues/Issue723-Ordered-Interleaved-Progressive-A.jpg"; public const string OrderedInterleavedProgressive723B = "Jpg/issues/Issue723-Ordered-Interleaved-Progressive-B.jpg"; public const string OrderedInterleavedProgressive723C = "Jpg/issues/Issue723-Ordered-Interleaved-Progressive-C.jpg"; + public const string ExifGetString750Transform = "Jpg/issues/issue750-exif-tranform.jpg"; + public const string ExifGetString750Load = "Jpg/issues/issue750-exif-load.jpg"; } public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); diff --git a/tests/Images/External b/tests/Images/External index ee90e5f322..c6980db777 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit ee90e5f32218027744b5d40058b587cc1047b76f +Subproject commit c6980db777e49d5e526b56cb986001d1a191acdf diff --git a/tests/Images/Input/Jpg/issues/issue750-exif-load.jpg b/tests/Images/Input/Jpg/issues/issue750-exif-load.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4753cd526e8d04f029846a5e0c1218e7136376cb GIT binary patch literal 36885 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

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

eH!0a+UZneWY@pg|h^60sf9kU`Gw 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 M+%@#es*R?a&pAak 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∓0-n^`wbRMS^kU<_L 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 z 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

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

Qu#kFgQzct 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 z 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 z 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%0A8SIirR={w|J0XLWlrfKiM5PrIDweK=^R+s_wp* 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ξ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

T|#y5~Na^r@7S*x{Wvn;j%k!@Amc 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�{1CQZ@jc0)I*2Op1q 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 z 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

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

l zD$Y$xS`(|-uW*bedzjf0CrmkDa0k;BJGG?IFmUmzNUYqAyLx~D$>ZPDRAO;3Sfykh zR4w;2wo~d$au04XPVyyrrjlSpMlZP;``lyOx2-}^>N~WBmODeXSp32S$YOHXB>RqY z$2dOJ+uX=-PHoVggmq^1Kgz1ROKl{wDGrdHnA@}-oOi(QQ_XP{cE&L?wakHDF!3>r zCPv|&fb*Ome@f_3vfLH)Dwj*92{VWW)AMY~fIUrCp4wZ8=KD0uKa^J&5M-zw`*hC+ zw5CQ3ixLZn+iNeC5LOuL-xxmrl<;0C8b^{iBatLf@UR7AIRp~DGw6MN>ngG3v7}l_ z77-rG$`p1C_W_kysM=c}{eGVH70#R|n%C^EB5yD(){;Q19eRQfP}u;CcFihAg&|`* zyR)3ca71KuJ;4MF^Xh7|-mp|;y1%(poX6$Lqy=ufQ;t^$IUVvlR!M3p%+Xm0Mv+~Z zd8>qkZfuj>cJw}jn$MHYig+iuDjD;fWR+h30M46Wx2Y<~8sf!gX&Gd<`C3Da5ZLy> zAof1>W@6VW;VvOYRd2K;#dj+82RP#;dvb7om1@X~>Pr>V2$4~79(XMwEXQ{T{3^ZN z=X=TJ7JGorDe}N(V}J=gN&3`w(3$3w?Gd^p(65$@ahyljj)i&Y_4lUDDHFgW@7BSW`xGf2q_r&TQ&&$lNX{{UK}B&{@d=@L84yOkSxW?0ETDvv^W$FQMnTosWjO>N~eToVjW zBI0o(s~J5=!N|ZpI&t`ysU(*6=qK{je6dJC<-eK09jdV0Jdx%yGRnXbfU37#9OsI& zZqrE})Hha&Oma5QCi4v(gpL;=?ou*3jB!^N8|sd?S=(Z|GD9p-`41#)zrJw)0C|Wt zHRD8r-eqmf*BhnC|v|`g6rWtm73F z62+AhJgo9d7ZGH9y!G#qil@3z9yE;~f88>F4l1Ox#Vm}_eXZQE{oL#@G1CJ8j(Oys zzSW~`BtbyB-qI>=c31m^pY#4jcE&M^S{d`%Y*V?Nz)jM-$|Y72ynB?7e&3#IC9{4V z2896H-udnN2aA0wiItiPeITk1NHlDi^} z78Q2+M9>vzo+1M5IXLymz|A%933#q1^ESr|H}2FNwohM9d;5wY^5scEw~E-wZU9*G zwUGV(2?#ni==dw<=mZU)xR9gas) z+qX2vB4tS(o+#m&TH;8t9wT2~2;^XAnq|8r5v(%YNP;lCqk%U@SY#&Q_~SjYYTCsd z&|M5l(8+4busf@5W6tF~W9H;zrfa3j$k}qnBWI9EOjZZTj(F8>N0bR+)DTZb$R9BE zKDAof+`}Q|$!BF&k&7!Z>x^W7k?UGNWV>5yXA)gp7TU6apvROL4C5FKI({d$Ak*QB z^4o8i6*(V28;}3*Rc=oQ8O}KBIOpDpRo*ma>2{iq)@-W7=XY>)#}bQC<%ra6!+#3;8bkIG91YWlmRRl4 z!xx%6X+(;kk~nTj9+|0p(P~kctHUtK83Zb?Oyi-?I6VGz!2r|YYkP08n3v1*nmnwr zlfr<#3O6}DihL}rgGR89O;4+eP z!1NsCj+|$$7tzBEMMSF^F@?F>!!A0O&Q3oL->S=R4a8xVDI@abZz*TGGZhCJ`HntQ z*bhKERN}_U-F)}DUpC!Umd;p9ZW-x}5JovU!0Ia*(rKYnoO_hzNUkM_#8NornluQQ zUCqxp@6hx9H6P7pZqhB%yE8Ek4%JcIp4lC$%*ksKMGoj~*UJVyxQ$gnBzghIKq?8E zHZn{5ru$3BoRXxkbHL=|pTJb8$#ekxW%-G|nPr|Zdj@mCZpw7UmaO^NT{{WxDtwtIt44yf$%u7vGCTd6$YWP$Y}stA?L=n9`Hm53zc*q%PUYrf9GIY*fdkg#cG zlzCz>tjGujTb%o2rCW|2IJ3cTAn8^F1QP(;28LXF*Rl1%d6qe}mAbD~bOB44% z2b z$x)mWfsbxzj@g!ZWVwy@q#x^(7-B|nGu(HpY9x{eH_vaqWH?on$g16P2?ISi;;WgY zw`-)4XAsY5%q4is7GikXNcwUQO#LZRjGOWj=DATVxG^i# z{G^aM7{KT&t-;C+ZfTNvQm*Io6>cGBV{9_4$}mCXV1t|w$J;f0^^zq4UM7))kXM!U zKmBTg;@Vkf%na&?hhwybu%zVY+dZmlmP4DtryihHc0H0I&XdsAII4WJN3`0~B^(Ns)8)?0EbsmLk@FItEyL zz@|rr;D7>-LFc|l9;c@@Au?S%G#+CNvc<7*8Mrtdy)#%i@;eTspK@!#7>zCFjU5E4 z%NS69dDlOI!K7JL9rvUtEudfYwUCn{^(FJbAdE6`X9scY2=7#m87WD{Z}+TyzsJRW=WBCa(W8>=Q=f)sJODArFlCi%!4gMB~3syusQig6(G z6}E`?=jImB{20y42Gu4E6K6Q6w6T0<?esTtv^d(m3K}k`gj`Jcb87 zx!~67s&F@?+mSlkK)*clC`XScV+^Z*O0j)!yLtkgnBS;FHvhV?5)EntQvL$lCFFOA55JtDiBm{J6*I^{#r7a$B7i za_UEG51Llt;n-0IbA?i)uN{p^Y4&L)p6*2}9LTK-+(m+`?hXk2YQ3blk|C7@W-<(k@IG;zodGIoqI{VFn|^4E3Lj~|yRsw7GSHb2IryNYCm z%#HSNr--HbL5vO#KA+OGgK&~Is~%W|%w?u)pO}k`D-z*yM@m~}ft8|Jg{r*jvR%oO z8iCg#a(L&aO;%~HC3KC#d1?l5g^A~>Imfq3k||7%mY-(w?OX0LM!{oT{yi(MQf%UH zkks>3y~V_eSed?9RX=tB$lFiU9aznDD%wTlG|;$(i_h~plXsX$L)>S!N3~vg zjB~Rul(!P&Vg@@`*b~k%{HmFTCKqh6v_c{Ns#uDc&s>l39`wN(`#0NKba|6*IuN6; z`4mPnlO~F7mrdNooXDdE$W{QB&u|C6e!rbV74MqG;fC$s=JPGqLmHxw`Dp5RJ-{7u zY8c^R^GdEnfD9_O;>RaGp#3R|ZPMylNS%<4k+61*x8?QyYeh+?xzOoe?9`5Bju9MD zTjn@qcW?_cbs&)00P}zcr>Qk8S8>Au1QegkA_C*fI6U$Q=t1Z`e*=wZ$L$Al;y)ny z@wq!yv)K0-=R8!_5&6<6vjRw(X+(P^EzWU{3FIEeiE}Gh=Sit-S)FH|74u9IT(Jcq zh!x$~@S`7r^!2FXp3)~-7D>(0ox5PLX(7U#Hf0$AgT@H;^rU-qnI}OEf#PQKwj4>j z+wksSh}g<~Z%5QfFe;@-uBJxXCBi10!#)DzvvN zwU#3?JI21wM7dSGF`T=D!P-m`zR-bwB* zL#nJ>l|0u9N{*vG!6kxeIA28q_$J6L(Vn`)fi(baELlk9UlW}<* z@NiUM9P`N>4_eZkB_>OX)OEhu{D~SVV2%h+kiTpralr>GfG~L=HhTUvj_nLq(;=0u z%at+(KQ}y&z+>~R6tptPjV!5yl`71lHRGx8)6>`9t6M`9cI^NW$OMgoA9Hh_c|Yfh z?WUs>CgQpXz>CA>d633HTrg53QIZc*0Y2TSuMoMpD%n+qa)_A5>WsvI8+f+E5Kz%d zW5H6sfZ%c4-xX@wOE{x1V|RV1O7{N%zP#0J#k7q4^*~7H+aFFU^peC}F`Dmj)Ye3yzr10tU-HUik^92%C{;dvDyZVfi; z?DD(~Dor<*rFKL@v}@O?2aNOete%5&T*ED7DIrs0c~DOlxc z8s>FEvfbRvle<57j)y(^RP!S@HOz{M8#;ZVB52l4(Z?$0Mcy-!+mLV#EJ9zjLbnrc zc86(8dvUc&gRpHRbvViE-AIOnLUFMA3k(!L|}vaU0N z6m&W5^%Tugze3Y_tqV!H(RQ}k3k6`qs2Srt{{WuwO0vgoZnB$~o-M`NVxgu&4i6Xr zp1JAGKwb&sW|if5W78G0r5?vsNXL~DPY{wzWZ2R!(Y*uZQAauC zqHkUPD#s^Zc&hiyDJ2Ri^s^=0;nB-8nOGQw|17`nIo7p0~p#=a@jxU zy*}JXlE0Rav~q@4es?P4jkq8VdCBzmq6C!5Bn_zAKw;as&j}Jp$FIzzkVkHvYfCcV z`K()L>DbGwc@)f;Qu#hTyD zlgRTXL}~UPm0KY2xg|*JfuGK^O}DEubmF?33ku=`_+FWo$^*@&svZbsyFt7HE zGN}bsbD01=3k+~iJPLx%)QQ7Q85eCVVmpP-7bJYW)Pe!X=N`n0U@*KvB~^{%k)5QH zK2IIU86$zg^*;5ic_MJtizAm$x0dJ#gtC|sq`N4D1zh&)k&JSCo}5*MDAvt8$ot)Q zNz^lPPa~)}{!~Y6J@U&Hw0q_l^3pbCEZFJq^r)d(qLJad`J;3@P+?4R9=RlBj0^$l zbL(0~#q}|dJ<9r9+uVe>fXlH$x(S0T1$>{GTMVRn5yfcTT-#2{2R!=Vdz#WV ziaM0lhs|(gx{o&(2^=UR@+OqBs^p)Sw^B(UbDC9qa4uzgIH!>vN(^Ttbo3cKa(j-o zUgp*0xQW4i%9-vas%YM>S^< zy!PNlKc6`}F3P~iAbDlBMwvDb#r+%erZY8^sTgs0X=?IBqiApBW23c{2 z2fljblho9YB1H|kjwEPM9yrRW>^(D1nkL*0m{UA)F8sG+k@)nek{f{xg=CE+0J5xz zSz~OF1_2pTdHm|+>~!Izh~tr^P4GNxar1782^e0-2h`+dpDV0#eX8(W+$(>tw^vni zdgL(#4EmZ)tLAy2pFSYP;E3aR>`$k+{{UK&+F7pT0(fm&IUovRme4e+I+jgB2IpZLM!3PIE-&#u*Gq5aFy{_HS zNZ=`6=ReR?cLk+|Vs(*2xZKQHWZVA9=rh+R`POy4xV4shi4;$K@JtiLfFE;G~Xij@t=mvHhgmdX%$vEY(UP6D2I?s`zs zM-iJ*xM3kOD_pMpGdSpR-22mI%-h{=9JJuHY(_y|{O7K5$M{r6Oxp2C$-Rl=e68o6 z!b62D3ho}5;QH2-k;ir9%PjIE!)dq$!HlkXB>NsX_4cahEbZec!^vA^ZN=269=PZ+ zgWLL28RG&dU_l%f(QSwf;aB^hdUWEnPU4%BwTaRwp^4{INFegp%864Q4@LCjoc{om zIFLQd$nS{SA+`@MC8Pd?RYz^i1m|iPfQ}g31Tf_O1a_+_b7*BUN0*FkP$Geyf}Z4c z^>JiV~Lyk;bqwnK6P+ z;tDdpcKp1I9+?K0GH;$q+97V>d1df(@Aw*pPus1<$L`V5&oMAq$y4)iKO6y7?q=Bp zcW^%Cjx)X~l(8qSG0u4Bn$1G*b5&BrGF-jA&D=KA%NpG(tjQT0T}SymikYDoB~HhU zlt#|tQp(uKz#WJrwkmg?}O-luatx0tc%wk}myjHzbE)(4CqLxaJl$$OIo zaazi^D&ry8C({@hrCeguBBbRbPD_If7ZI+}CIo0VgSd>IKQ5xN7DbtU!Q{A% z0AzcH5;C|sBp*!j2W|&y(lM)u>!n6@~-dDpji5D zV4#q2IRF!y(Kd|Y?0E&e@xmP~?-EGI-jd=lvQ3`ca2vm+SiS~TS*|v$aRpHp)m`n3 z4h9F*{(Wlw)q%(xxZr0VzP1gWz3f(#&p5Y+Ia*}hZ}T$X zfH9HJAoIr^GgTUV@HU(GMq7_EN8Am zihH3XndaZIR5HY+jHnAToPqg~RiL-Fp58YRPA-+(&Y$f$jez^0CI$~&ocA0IRfBCL zYTxNjk;J3V3c$w9Ffwt$?lL`Udx-W~?6zZTaO}b&vjtX@9D*_Paoh3jRUOS9u+Xam z-N!1dSAig6te#R6BM@?OPDkbM^{5i>P?F|y@tIy@HYLDB+Bq5Acx+@~9Fx#zik{jP zh_rc*Nz^MjQg)))@87wrvD`$iutOJ_4qwZfX#rAOt_Z=vBOo3IeJPGrnf~(zjL4SJlA*9T zUzm=0$0nIPP=|>U-*k5g%J1B%j+q01bJ+9JxTh&|y+K`}=1YMW+2Pa!$L8*m(A+x4 zvT`>#8O{McyZtIR^U@D{NLW^r{K z6Hd8VUKv9~rE&%saKk)q9dqwm3o3y-ff13Fk}`xch2ts?I%c`)lQONWIST`Fr@s8Z{gYWB6D#;AKU~lw^gL&kE!2baCVw{S`DP@_QNe}^5 zCOAKrQP`IsU^>v7xsNnhlDy;?Emb9!Pn4{)n8950&JR6t z_*9n>2&IrDXl0RORss25I}d(&_NiTAQ!y3#d7`$G zJA1TInREBv~gd4B`hsSIhx{ zAoN0VM;&p2#(LE)mTM@LL1gnd;E{lEazOlXO!MPwSbs0SnS?e(sFlWl<$IBEX?c;$|AbDs1q?1g`Rs2JRC zMn=X*xcYHJf=H!4V$?SU<&BgOQ!4QV1-Qr5VD{&?H6)jJ21bot?jtH1X(c%<+3G+T z&QDr&Vn%tSDIb?{ZWnA=+^0Q8IUPG-(n`e&N|C~5mLL^nVh22D1F0Q-IHEARH@ZaA zIf4l#w+STbLrAhjq=obwfgNeql1Fx3CAdgLQL4n3NXO1N$yC4~9!dGII5i1~#4e`T zW-V;0Lt&eDe00W7Kh~e-UD?JncRX<2Oul4MxK(x@xyU?mpL$b;kuFhemP2Y*TX^l~ zCo8#(z{XUQz!=EJI@EG3cNX_C#}tvseaHE|tmt$!jEl`N?mBS%U`LM?RfBbM>p%`&lIsvytSL zNEt_%(r30hgVzTg>pCdzGQMa>ZQnKl3|rIj;){ol+Tt0ajiro2%{T8#vbIJBIUMu( zR#A^LGf-%nc%d`yx0+OG$jomsXv-+$3F^6iLGM4TO_nBjp`6BD2i{1CQ@9-W{{TH|vn10> zXNnnMX;L+YIY{J=;Cdds^V2nI+UnfMQf8Pfy0#S*F?k2#2PeH}B)N)}`9+#&;EX)X z(6jCPJS+<~PatEs!Ozp$qKV^sGRXv{PqeW&5=siTdH}e{Ba%-}MmkfZf`2*^A`5ON z-0w0I=8owR?87SAIT+&{j959$Lm^ZQqHheLv+dK@nuhe;N-od@(?$2OB#{}`kM(h^4tx{WwR!fOgW?7iAd9%5T54=xY_oqb^lcdaNk>uaH zc;w4vNbQr;{7q>GCXH#g)Umy+L5?9Jq6K3jFbvWDAn-@?s`9UzrL6(Po0&|5X<~X3 zJwWYGisn_8*U40QP#vu#O3U;)$RPS2J-Mi(E*+G}5(j47+1jfh?T=BD{!M8fR&K1G z!o?ht&oEF#sF(#fB}o3fikwbVBu@-y$%TW$3(+#(VKg9L%g<;z-y=jL=AA#^u2Wb7WxW7zeFR<`*(dgU^-WMTTf+ z{o1fR@q!8JIKlVh6_jd8OO`=*b1vm%Ac8!^fMzsh18V;O2p^Yv(o!W)HtlUqnhmXM z1=_TXdf`AM@s7O*9<@??!as2y!ok5LCRk(Ccrz`y_j z+qZwMXI6a7-V(Ji`$)QYe2vL&uqsGOk(mL{9eZGL>G;(tq`XmDY<;c5eZ8v+CdrPp&fp;nz4;Z!E8+% zTiUmj8a0+_14zGlq>%T=e@xIrq-`ITH%B8e1f9yqr`1ndj%!8|q|lfGHMkkd zT=EV^(n!e9IODxpX$YF-{Me_AK#b_4X+wj_C$Dbboi!Va+fTWb4ZP-7-3+RCZfl8I zT0EaokZR(iZu=9uh@q2mj0OWeKyT&ss3N#qh~LSbC6*X>UPc_BEph-S&=Pu|PtL?q zH}3*T5t48gPd&Em$O=!n+A@N13FUqDY%C!6BN^IyeMqRTZQe$^iZ(_`!BZJx8Aq;q zjQZAuYX_2zBr3D2?UC1pVV?g0fTAi%?h%(aLOG?dU68?KKGzUMS)pGq%a7b}3Y>KH z0QNN4T_^iPTS||K0+5bJO!XZJGmn6$Ni*GTJ z5y#n8qZ@e`UV*YYj%pc@sUc!wQJBA$%FXzppNxplglH@cgYJGC-olR*0W=%{nD8hk$Dc%q5~@| zc96uyj?tdKcWLZ1o(~nGWXw?lfGV-bD~2HRS?>h#PkJqGXKN7aD2cvRmO=Mfmyk#V zft=$etVZ5&x8Et2I9M#LAvh89oMWNMCmlaJ=u1R%Mp8_Tgx|Xd%t+>!1b_|~2M6d* zDo0?#D|urovl6jv?SY*8AO5vSSgS{FBA!jSZ{5aNs-9JkqMuXiRp8qX?)Odhg)G}h z%AMIHsEZbxDZX|3B3Kr zSz2IRu{p^HpKSdrEn|`gH)nm#(G4W1SSgYE0!hYtcm9=lFPn1|5}6cBD{YhlLbqI= z;AhgQL8fiYqj9lZJmMyHG9u5liG#~>y#_`&Iq#2JHcHSp+vc8gXgrH}!x;j`Sf7=NhEawZm=Pvl7h8-0sQe1RUoa=B9+Ll!dZx1WEF&LuqgJdB>)=bEOJcbBy8J1s_gOJVZ)1k#)Q6A<RrDPGzV{g=st)jrKNg|dcNrN9uo z4yc~#k&)=aq_m3a=k2pLS}p$ox++63lb*+t4m$SyMqjYB&*!6V5rz!eWdlB+k6)!F zwdUD(TSW}EuE9mhIrBFHLx4xi`HnHxwrJ+NB3LA1S&O4bC@%XCm%!wE^{28Dt&pVy zmO#1ArRh`i>B@xe8p$VS?3>JeFqt^q?~@eB|`!(xVVFvk37i3(nk*J%2i} zbqhukOOvwMS-;Xsl~rtHjP>ASG?B4)w(=R6&VFRJ$poC>E_(LCHO(hCu~MHZ9|gLq zHOy*NOBIp_aLmzx$p-*(*&us!&1Q+CSt61#ar@v}5j0E~DE{_F6}jkn;QCgb=(;HC zuAX1Y(aMahLV|J*3FPCU=f8TPBy-ACTwh)^a}w_uJA#ln$mxUY)MVC_xr~)pa{Q33 z)W2zsgG%v_HAJL-+7VYd5A#|p2NCFQ=&%bbP-BoIeD6HcDeLg85!86IX; zE&{6ok`EalFysOJ=xwrP8}%Ycnf#KcdlwPN$@1q11KXN#d`l=N$RbkF#9Xl5)6}2N zpLHD8xn(6{^M=(=?_dwFtz4O4P}8%)FgsL-0l#<$^BB+8r=icyG*i?higt_a)_zd( z!x>D>(lc~87z?zVpI(F1)G;KPpLz2FBJIZ;Sn^3d_~Qe;SOz%~38j~GDY;rU1Le;k zp8R9Cy)r9#1{tm(neQhnECE=^il-`h$Qkt<@NMxpwRBY9<`|_=17P>hTzh|w zIg7?ERh1aqpO|p5@IR-isrIciqn*g7<;5e3SeWfYssIidy}R_QX#j>_A=zbxhUY|V zg(HAR^2qn5-P@qLF)OF<5RxNY{`0Om$9^;Q#U}fffIX};A%@+2_Km(`IozP}!RgK` zUS(uVn^q!tTV2n*ZTnNTx)xFx#4%r(6^Z|89Q|C!; z3eu51sap$CDhSYm${&ECM{d~1_*C({kbR}vHP4&5iOTL?zmHn3ZT!8_G_5+YRt7~M zC?hx=53fG89FeZ*+svq(a9eclP}1dwD0do!r4J1I=Xu;Emo{MG}9|yKt;?m$pn$c+m&t% zO@;)IxOW9@jDmMZ=EJ&tk5y-s4cV-$uD zB$jRH$?_;3hrS1Tm^I2cPm@U*aYhy9({2vNJ_43L#M40F>50As#ADtQgGt0MV^ zMVE6*jB~ZI)1O>otH~=I05?0bt`j>{XQ2Ajv&R^USsl*jxm+m+ck<|Snk2cRbVb5Q zus5ck{{Rx}Wzzh}6=QIbQ*7&F3=#5}#5e|I8{!AC=mK+SWwxFZSQm5h?@ z?n6Y46~w!@JF1n8bNxS^N{bY%uGw97lBP^302N|zdV29!Wk}$Y z%>qf7xXUD)Q~~M_9XQQP+#s5YE8M*644dGZNtJ_nk}~a8C*=w{f!`)QJcQWk>89tqcNdEvPr-tCFM6ncsrEe^x;6Chk z7(8V1J&p}Pw=l~E#Br?8oG+O)W+v!y^5@#GrIRYfkQ-{8IRK5-+NGhC^<`-mUEwti zh7x#q$O{?m{(b2#VVBB7G))1vQgF+bbUg_6Ac8%Jr@S&Y$S0HJbyjB1eqcW7@6=M< z-nFttaRP^u0v1@tRlK$!H)48oj+}E@x!hFTlM)%iY`3FnfCjlc-Gy!tBp8Wg}^~J^&tI z#y>Cs9QqGRmnNRZe7^A=!^Tn8Ack3^Um`+*iu3v4^y3|U>QC(TnrIN)$a11N1c8() zk<@hQoPs^6w(*V8h{9Yl$~K6&+NAIedf$heKQx&N!1Mr~exBm6bCbDo zih|h7@ZOI#jmYwhqS`w`s3mr6sm|fgI5|9f*QCWB#aLmuc!ocAHn!Cr$2jMlW9wDq z5X8ns8xISH$6s&DKmMv%q?M#31QAA8<{&XvC$2h?^!D|r)tnU^=JwFCmUhU}KF>B% z>`7)NNcG_Mt<9-zZ!B?v8_b_G0y1(rALI3`dm|$mCD_DHHmaD)?Z-0_o2zQMJq|3%o$=ic-p~JqZG{?rq|O%7WZDCN`SxK)4%M zf;VFToQ}Mn-7{UA!oFY1a27w5vG(g+&Zh)$$G8R|w{Lyq;D3|ax8;V0E!~_nnvLDj z^RWOHsXm9d9fe|EY1a2` za{^r5Mq!0iMw_En2e@!U0zJ6o^N~g3bkj{(t32)ik~m(nH7)v?3N^-e%{@ys}E-qMr92g0rTX=7%I)s5#zJ?LHW;_aT#ylHVt9 zUc7%#=~!}I=}aHYv}k9MnVKicsZuz{IqBgys97`*1=W5}&Af7&liiX-}Gove=-l3(!&`6R< zkV+#yWy_Mw9~`q|u;lU0aJSa1tg^DT$Wo#eLUzc@$i{Kcf9qP-UM-U5c_VVEE1>fC zW0DUeA57J`?;^QYc+pjafIcu8oBA5KsWrKqgprG(-^Xt}yTk@#FYjR?w}{8D7#Spv z{VS~0H3n;VSNC$5pl2+FV`pq+g2w|rhE6ln-_N8;qt)e=u<$rm^Wz8RQ`CDf@ASyd zYQCv_!5S2S%PGO!0agIyaCp!2;-$B9rBQ^DqBTgZ$&!0-IKp||a3kH5$t81~4sp=& z+O{87(-o59D1mk=zEraY`EWW653k`~UJ~+2yvLOm5gclk>lxfzl5$Du&~QC!9YQ zeo+CXVxXLL&$W3+_J!^3vYX|G-tJfjn+!KbMUA_F+d(6P)j{^9hr}&7FEzK46qx*` zKfEPQH*v-eGBfz|Mb3X@(dZ{%w1PIC<%&x)l>-dK43G}h1oz25p8~P&wL4klRC&an ze4Cy^zc4xL{{ZW*M^M%l>Ilm!o0gokl1}GpsXUT#oQ}Td^Q;Nwc${$aGstmrGF3-! z){|<*!YU`BD#tT7{C)kIrIYMWcWvd(Bw(CwP*^VEgN&cjr@PaXTgD?%8#?ZWFEDLf zb{|f{xH~OX>}5OUGMEO|E(YDh^dRS`{*`C`6Jv7e7m$mYytwlrQ6cJa!N~)l`g+!H z$m^#m8n&{m5Zu}9nGO@lk{)u|=O-Lzr}@oTyeck1ki`B>i{)?`l#aMPFnxWhjozTO&iV%M$D!i?UA^XpHs(L+rRN5*yJR@nHb@T82mpv^W=pgwL25dhB+EY(f}2` zG06P0S!U_refGN=SK;A!!;mwb-!MLy$mfGo&8f%Ao7DEbKUa=Kj%m>ll`2)hC!Y0R zQq=5xl6EY{A`i+yWgdf`{eKUwd7OIt92xS8%a@(719d$*f-%q5v%c7-dzSk=&`-O1 z-OB#}yOKUI6b|_3C#c3cRqkfsu6EBn4fb+x1*|f|C!H*o?8_Stgq6=8{dxAR`&*0H zztRQtQpF;w$Q4iS`T3ZhcPSk7&j;4IOKY2#p6*1tnmCMy%Z+3zHuNjUIP2Fv{i}Av zP_hzF7*|Pr<&NWI4To$FM;LA}Hx4)>IR_Idv{mJ*xzTC9DVho8jL#s3NQi^WMl59K zoZ}ej*WR5Mi8dIdYm+lU@}2W2l1%cz9y`r^tN%flx zjnTS8Ah@|AR^P&qan3u8WALs5J4^VXWwk*p%16tz<(t>I>HMo+&rO)F`+}@y-Nts6 zBcIl()P2d6q4rs+s!wYqlE)lsE*>>@3&2&z7msi{pGv@wP)2i?Xizx)+Mpsrqm1+* zgZ_D`?<}_H;DPee(ixVB4)B)OSx3mFNPhVR0O*YnB5p0tAlf1JPk(~moA>*6?2jNOKXQOpwUH;U*g4P?E{L>tpyr)hJ zFg&W~jMNFJv@Y@;?<9=BCz=iv^kyALIUIWXS4R3pxwbx2vbxL|Z*wGg{v0oCbCNwr zrE(V*6C{$mN|BXj4ug`*laKTDtrn=lP=hT!{E!I=xR1>;{Ng!$z^b3^bRgvP^gmj% zm*t=l-ADpR-z*D~v5uz)jEtOt^{!4Ud1ErXCF4ayo$JGWDT37QE8D(qgx^4#q1 z-ZLJcvE1AwK@nz-3$HC&LVEg~4Dvc2^^>UTOp@5>A~sGuX@au>xUr# zC3fR(L9Q25c6jEP0Ti*e#J0D}?Z-d|r)t%u%886^Bhg`dIn0R^eoS`J{`FyB-GImC zQPhlkn#`63SXjrkLP$_2P*fh6{{TIGtIsVp`pQSLCEfD&ZU-5 zFp%oTG*U|+FCM+Q^sLTz?(T4rD`DVtkTkqVg8+mbF`9bW$VI?~iBu!Vc@7INLNGIf z^{d*9dV<q0Apo@R+gElezCk8Q#N>gpE`PYP;`=H?MCy5+pY zW_gbaia(eC09;UbenZWsT$LU)0Slga965?48+12o6 zOeAsvkjEJ#80Vbvj^5Rt`f+<`j10wO!p71N8KftZfI1Kf!0DRZNTfE>K_ky`JS@u; zvp6KLQH%fwIsX7TsWli@-r^fg__Yv?<{U0m`}W06^)dFbi`?_+p`Lm3`_g{Y{#x3( zMHm>{*N{CAt#lUBY}o-O6`2>xwuyJZ^(vWSGiM*qQ3^*Ce9_RUS?Mb_$6r~Yj zmQ;-*e6vaydv6Lj=cm3g$MmZ{YEI0EB7sl_k{F5FgC}nUla9C~)C%!DqAje^v^#{G zK*7Nyt`AX;JDQ#(bcouyZN*iZRmR{zr!&lT0l3p>Q%r%#x%#z@B; zdXGw_Cz&ZzXLSTk9t8emMS`w-?iuadewMj`F7l?c*rQbz<;bgtPn#t5lJ(5Pu z%r@ub<2?yHWR7~*=kLUyg&OyVuYT5zA+&3bZNOrx+=0_M`u%-t^#&_>F9zFaoCR(t zEIvjcsYt?FuAq3hW%a97 z7zDY;LR5ket`GIEdiaO%BzTKepHQ*0Suc_hsVA4YR1=ef)N})n>0do+UKrK<97I}$ ztwy@IKd~5oOaLVD}tq&y&$r~)w++GOQI8)Sv)L{>3k|PkyDnv?^IP80V6uIP?@8fXJ zRNAuC^sff^-U~r0wfq)YvkN4RGbEBZAOuwz%9SsYanJ+QSFq`KZ7%uWQQAc6){2tg zZN_?M9RC25U!D4{pQznjz==FttYO^OQpSIF+psVJ%K!#R@_cnZX`Yt4ywD3^tr)iuCboHg)9wooOS#oGM$-J;8wj$+m6SVtE@sJm=o9=CafZx$@cz zhASrflxZ-e0=xn;tT1}?t;I`ugs(Kank0|x>f_~%4tV+=YiPvD!cFW;HMv-zxeojg z^1_mkLX-1ybB|2cRKiIo${9iyZ!#n$y7$NxwQ~$g#k|KGZHq{zG!2(;u97hQX z?Ttc=0HASdKcMYi@ z^f@eb1a*a#h&$94An-;G4sdxDz|PlDG>Ja>XSY_8J6ThfUD*Hwk;owP!RuX?qLHYU zceydnZy3b`APO5Bb|_Fg<+=Cmfn03X@xkYoU$je%ypcKFtJ7#1#tA%=+zO_pC%Dw2 z+0UCRC)5S>mp0edQd>6Y<2my4k%nHX%G_Z3WN<}!z5Rqp*PcXSBw1D9CBRb&>z?Yv z(E9eS`%`ANfEZJBYdZO?rz}(+N9SCH{9MYoWb?_8xl*ihakjZMBNG6-S&KhGtsTZ*iI-BR4}a58h!oEk{)rCKqO!`)e3 zeTrDFU(1oE42$IkDw)71AHsP2>z~zZ?X;{smk>PdksJ`NWR5_2ZR3Vk7{(6-9>iCA zR_@|x)NGNBxNDCwbGPOsj`_gHr}eB``&e$w(M-TT=KDF4Fr`#;)3GD9EJTw_LswDB z96h|2^4(orH=3v=jhsypk1jA6DaSk<=hr;(UB-zNPi-yTqN*j_zH6h(6uS-vM^V7) zeXEfB4T-mVxt{7Utsn2)vX^H#QLy~qFLHR~X1dKP-VKcylX65pXrsslTRi8JkUcBU zg;&gC+ef%)BGqR@Br&A&TQ0;78FD#0Pk*m^-n?a!$|RX}2fUu>8I7u|LmXbRGcX`$ z3&3oa8~_QgJ<+xMF&&&KKa@;y$EHG5jmk6fsP)E4&!Mi`8;g5ZSC&he8boHg6R6ro zdMU|2m=)+oT(;b8yzdFIjdb5JNgL)asaW=@BC{tw4WW9#kHVOyb z7~O-%117qw2%g?Fxr*XwEnUHu%_aq8DoEVp`^)nHJeJqJ&^k5yZ{Xsw#+ zGnou)5kD?Ydh{9YezoXU?Qv@o+?#pc)B?*K>=s5Hv5brmbCP>kqlbqzjU!6!ofWmi z!x~L&k;p#zO6G;PuZO{cD5PCAhn|^Y7q>)dOv}h6`~Dl^^V=132{h*I8)K zaE{VO*^zS)iAs`scK-l9E1TACE-$0hV`$||Gio4?RLZX5-;7~~c_Re+^IBHsQPh6P z##<9;dc^i^Yb~^r+D&ZC!r~GEjx&+z$Ri++L+@QZ&b0ct5lMW`$g%k_%{EI6EvkI> zjG{1cjC{Eu@!vh`&ou2T?Q$``o?Ch4mPz4h9JG=)K5V~Vy~tDB7_QnYC4w~6QJP62 zg?5t|F3i0F2ZNLARqd({Q>Q2`4{?t9W`QS&F3B#UuyAq#=d=g8oJz|ZPy zLN!;i`(h(UZ0Z&@RQ=kpJgS~}!Ct)c_}6N&3E7%Zg3af{4ZABAjnSMkmCqb?1Yq+~ z&mWWKm|0-+E)}G=g-Wc9G6%6B6Uq0gg`$c;mb+q-;!W2KxWgO|W7uOpl{TMtlKH-C z?OEB83?LE+>(}1{Bi^4nxur*Ri;+8{I?P-}EPQTkVYAOQV43D)uq=B~nSqcjdwIwi z>&LHLK(t33RK7@*UJ;=A37-Nn?e7&+eVWV7h0ALV$^Unhv z>nYu{BI->Pmb1mgINRlryef_e!0bhIXUj{EvsrzFSS_?o43=#nC7Y7FWC4ac6Vr|l zdg9`^W|>hupCqd)#t2qsJ<0qyA75IvV{>zFaMMoz03@ZOiLhCVb#8nA0H0cLNe-t*GuJ0r~~cVc+X$Xq*!3MK^8YEOTBjBXP$%G{A!Gsa!6y1BoMQ- zpLYwjdjXz?mD5Jl>9e7-l33I$DPb5@l5BFs_2(SdO%?2+V-Rh4BLzzs%R2L%44eQ> za#mNdGYB)bNH=a$KoVp4j(hgSbXG+rXcFC7=D6t`Dp;}40DXE^iN;9MbZ@#O)b5&n z@R!{j2MV$bVTc5PagqmLKy%)?Je!+_jyYLOWDhMzJRY4p^!#hEnJwLg+{R^vKi0Z} z!J9bf0X!b3{0(t;cJoB?OBsnHkxYvqe6axZBal0sA8y1{>0=sE_nId+a!)w&HoHR; ztBAl~E-`?4>B+#yQhn-}iU4IuB$(WJo0%>p+!anUgN~dM1q&ozL!?&l-OnrTvX z+9P4rPdf^>dSf83TyaZp70S73l@|;{EXqSv$J9J{E@;K*J-5sMj zW^a6S!RN1~HLbSG_tHm57CD{^oGx%l+t8dGfygt^qDdW%K}J-yGId zmj*^HGNf&6?6H+OWhC^^QaJupMixN??rWv1y~4b508%z#ADk4n&`vqVPhaq?>7sXv zBq&no9l+py!<^^1Aoj&rj!`Grwls?>vocTRhQT}#GyIK0R_->r^O#TbKkp=rd4!&) zcfX+b^`>m$KE%YjTv=Pj>$HusNsvJU1oZlLq`m@1@8%81ea6ukAoN`4JPiF!Q?@T9 z!bg;d5>*f#iWL4lR=Yw2JTv)3MoP#dkz`W+z+u52j;D{beZ{JEBh*)kT zg&d#rk9vYx;#*@BR`W_*DlOq)1CTydP)Gpw$vyq4BTqUxRy;==MB5M&0)P*$Jvvoe zXrs4Sho2+LuEZlVFkJcqcp0Y-rfG9Mix7|>Zq*kTE5wrm(Z<|l5(jMb>Us30q&E=9 zbv%MFfU_)7F(I4O=L8(~sXVZ^G00e?J3x`yh9hrZr{Pe{?-CRc-V~l`0Ge3AjgL$z z8R^02o@%U^rxdm&P-nJ^NiE@=q-B7YKPl&&4&d@X3ZjxrD>b8*wOglBQdJ>WgNDHM z2S1O!Xo+HuK@>sIEJT!c$!0v0pRRcKs$NaBcF{`ggvIko8FRaKdSYB$Is?-`hw`Zz z7id;cVHUS&x#vHtEh8(E0s>67nS^7)ri#|pfV zx=FWWxmG7`a5`ijc^}fO+$Hey9Syp`+qc_CGYKOcY$0%dRvWN$o(^f#TTEaRmkuou zNh7lymCij6PkOku6RALK!^}v$(8Q}@)BvEIcF$hbT3Mr!e#yFMq-AZgG-b-K8Oa=T z#{;k7R`*3RAXQ=`lXANN2JUhCR6k~x2^LB2Vz)`B+!oqc-ecSrQ<4;w+mX|Q)~5QH zN;0*IB3b6Svv}>>$&9a=<{?w{Ip(jHVRPoD(y~TT06!>hwCUPI_L&+Bx!{dI<%n#D zImsm873UcB`c)V$ytP>&ie`u~d`RT5JoWFvsO7YbqfN+si7e3FdGd>CWD3ZN2~{BR z*E}AcwK1GS9Jn50>;QnW=`fA3>g(&VGR6qn$D(PV(4=)uAWKX!l2tKg=a|#!uew+wi8Oj}ScQmbdEUV0RI3Ua>pIdB-A;)xF>1ya~mvk#)EcqoO7IlIQ(iLk~C2VxQ1aX z?U|4jWsrhE+DIghK_idOimSEw0#W~;(NF%@0Rp@LO1ZSD9V^%EEGAfPT z_!t5F&NPx`yt#{X*6*>4`DE};0m%8V zILA5ZQs1sEPc>F3WYl2itBbofI-(;F-fmW9zAcLIXbspoM)mBX# z#-c7q65BwxY?I7(D#RdVjluQ9br{G$TB&elTUBFmJ<^y=a2W{9dE~0#3=HJ)+?u&1 zy3Ao?&+gj{8*aink8phtx1}&iZ6i$y7kGpfEB0fxoDIWkF#zX|NA#>?K2o`vmeNYC zZ?@qhgvXf!CRteHBPWsvq4)LWe5WS{P}0N?4(g#-lg3X!LDZfq(+hyp!YyLBjFmHz z_>mW!ZRfvp>^*9&>3|<9C|#y`Hp?hbNL+lRj@*vE_0t)&b53o`QqsILT)A7f6POgR zn$!gndl1~`+zO3jnr9CwM@I@Usxuj0r#uWEKVMpnQr5|%kw_C|R!3*cOxto!eMg|} z^r`M8QeFJ8k~-mmA1dRXJ#*_xGoqVPR)kc;ktr z4zj@kEF^Gn2Tpy*^r>P;i4g?ht>snnla0eYK%(MRNy;k5#3JoT&|s14@9XPXt=@$D z=&dolHsIZbn(5t(tZ{5lFBngk`@nTS#CgEyEr}euFxX>lxh3$$dC135d-6Z6XsgL2 z_YW*t^P^QnU%WvczlB$8WJ%IvCy-H8h+~s18*UD9jOX9^;+BNQeahk{2hWmd_QZrq z7nVaP{_#Bk{{ZXL*==s4kinRsUJR<_?qi>v{W@{!Rwr{3PSG*Mtg0E`0i$jh6OKFa zO_170ZymBnYaS5n9^C1Psz##)`q(IfmlR*XAJg^raBA zFfui%5iE>S;xMI4V;IQmkL#bT=39BK?_^d%JkjI7PkeAy>>>GYor4`FQ>yR~cc{=B8l|$+tw2M4ODz z!V3W*JmB@f{{THI)KSSLfM}VbkcJlO`Cy|Yj^m7;neR}9@*t68h<%`|86D2-XYX^@ z9@OutvNP?5?WmF%t>Bk?G`uie~rh%tI)%1`_TllD@=psy0$3FNauocLv|un99c$dsTG{U!)u(8 zgSh*3G{$+#d7Cn)_=qes>r>rZ-rC6*m2%dHYk4w2Kxq|#1QU$ljPdACtv(1EXOV@( zn<7?lc~H&%eQRi0BL}P8jLRf#GCLt@;S2M{yXD*o!TuJ`I%6XvJer;l?DdSu%;|CF zkDTF#JqI4W{{X_Gwt@wY;9XuzE!uq0qQ(L;l1L|sDv;q-8LbE`d~%GBkCkTr_tbJ}@wkz0$)8{;{*D_Uf--+!N~EG7V0_OtysI;U5kYSuRfsv09uwPAc8cI$a94|SF?Ilk_K4F zERPtFyoC-4&usn_Mm)lxoTP@v5*3&%;x>v{_Qvd3Os709IuVTI_8zrXSxHG6LafTc zqm1=q>G=E6aAa2su{;6dG6ixA9(c!I2(4RE=0O={S?*;>$C@01?0cN>IX{I? z#>J;wYk2S8NJ_M3<4t9Y%Q?#l4;krz0qS|<1_@nWB#cV&$R$<#ps0^L{{WHiM=We| z)Twu&6spj|-)T~+PUnf@+}J#TGI-|)K9un+ilF&P7>$_i$Ri%7x8+Llta5p8Ays(C zlmiI~J#q9W^r4Z#+6XG-d00{veFv`;Md)Q1xiL(VeVXGN!pvg>X~+^_;F0t!IQ6K! z=|Us|DGXN8s$1l4Ss0vc9ZpxTJYe_1seH9?tkX#tX_xnL09BjR@Opn!Ni-5iD=I&l zQf;z018Eugh$H!mQkzFgc4MKCq&H;pA$sV(CWr1P|9GRgag+;;hy8T#;g40Rm#sHIGV`&6Z* zagssLPK1hlR;zaCB%jJf4VffAy98v6`~Lu*)Fj_So!xaDt2Q)08Vk%L=Z3x!3JJ6*QM zIT(|L3^GPf0|3%C0+|!cV$rJw$;R(f>&I$|A!#k7NL87HfnwSVHtskc*4(TVit+ydtXG2P z1+7kFnk87_U~z%Bk}xuJ&PnVAXh5*XHX7zRB9WI8#u-C4GE@cwk-Ly79!5Hn=9dTKkiI~EU%OC~3%wQGI1Fzvy#W$NX$0L)7mos)JoR6r- z>%}CwWvR_5*`YkUW}jm!w5&$R#y2;z`_!a2mWv!~BFQ5OivmvE5HW%zGTWreSsq{V}YCkIp@@7sS8WE{JGM3 z;J2D~Mrg{6upcna4+I{A``-0i?H3VTIGJQ+>azdEkx1C7i%Pu$AH0yAn}}xW7DoG$bxBZE#|st+AXcI zP=W_NPhLH#mg97gySC^aDGRWK7E_)v{o%Kt^O_`B)l>$Nqe8+5kQm&k?!a&|58dtf z3KSK>`fNva_88(R3ta~;JcokF$V7zTX9s{zIr`N!b@PGC7gY%|AUMxZasGIza_o-2 ze9=MswrCOY8x`nr>N0uvHDU#ZS=M!qNVc}gN-2&;<0tQX9C~r}t-YMkoO!wn2$fhA z@|9zkJ(aIOl`>To7~h9jiXd+f%om z@=a9RTbpaAiYr@d!*dMiaNc2&fGWV`1zfHPInPZ~8%O)caD3=Lez@UVJY%nJr-RzE zsP7|pCdcYc1;Dp!+g~=qKsU#2C{`*DARHVXI-Z?sfP95h0;RUypd_boT%JihgY@(j zaoXYHWrjw#5n~27Ab@)3*z@_+J4(F2avYJvlE9zy{OT@_cNcw&QMOun-B_;0RolxD zJqPuw`jm>BErLpuNpl~Pp?+0d9mJnroOj8pPHtzpKfAe9K&=_Jm7`Too20=Udmf~N zPt*+ZMHI|dVzcerE0WEgxjD)I06w*(CXvxa#ytit!btFkv`c3$%CBb9Fpy`fZpaPW z1CBnmuINezKoe;^x?u6fYcAH{yh7gHqqK!CSN$CkniT^fcpa1yGtYloxiVhP3dJNs zW`vAQIF2~j;7uirDed~>zs@c$A5azk_Tvn>2Q&L_%xf)vnu!JBlW7B zV$Nq$QZr?M+O?$W;M=+}k|0W$@q!0Ek2o366{TxDMkttW^4cKE@ACYopdf%j>(|@T zqrXU2IHX-h-au}T`Wt0r*~S^T+6P{Q^f{=VV-C^GTTO&7FQ`r=V8rKsS3fEHzz#s; zsH}ElP`VU`S!X zjoRiW#ArAYHaxz01xO&| zQZO4U&;SQRoF0Gr^+qczcDPnpJmxILONi2N_q0c~P0< zb$p^drZCbK$UF>utVrrGdX9&lZU}-4v}u-Ggq4^g0ycxlABRl+aaQ5E1y)IBf(hY2 zyt9luNLRBSF@kfBe}wTwYDrja51GOZpKZI4yhWq8l2j4f_9%fyc9WLmlahNHWPxU1 zF@mC8BP(vmAd!vVUID63O3$)H8I`z{p~zE@(AJwn7usWq+1dwF^Q4F6>(~7HQ0I11 ziCrQq3654W%P`#~+>MuGpS(|UYFMroAKgZ`R|b8aR_JjfE4RpYla)O_oYc1Vu*@zz z<(fx^*@eEzmNkzYjtD!xUH};6kH#?8$pmsj`FYu6StVbaC!U>n9Mmh^T&~2jz_HIX zw;N`8E&wTVgCL*Rwx6qzcM&)b-9l zBOG)2R(;b?X!jCZhD&ydOFEsqc)dLUby@ywTeU& zDVz6m?OS7U5CbE*AFe4)%c-kUyKJrv&@%XYlPY%K3A0>V~lql zj&sML2fbq7x?v>wY(r>%(%x#bt<&0#sj%QMKY53^?Z@+~Q^y#*kr{HVRfxyR-lzH2 zie}1quO2d&W;Kn&Id3sb6P$Dhp1twyRb>r3pWVn|fm?g+EF&5Fx%A2W+unsIc2r-y zB%V^sXt4=ojwJ&M<)oXw26zXz;Z{^3^O87>i#G2uR~wjro+~-Tk0jR6pCV5ubV5K% zfO;HyR-l$Cc0AGu6(I;Fw1BWOfrT4#2pQ^6L6h2=n>4Z|N4A32Rd&ac1O(T{p-lwtu0P9fFnjyzhrNoENk!+e=QXT7lyVk=@54tc|rqBLJua zuc!Y2U#&%~RDKaHqA47)NMaJmWuLd;dUNK0!P1_KCueKGn2g+zuE4LhHk>6;jzQjU#GGV^eZpg0` zp;%`i430tL+qc%EOGhwVS)-(vP)M%I-!a>qkJq90s=H=sB+UT~NMo4oGBm$3xgk|g zegWxKnl&<&fed93@AH@@BnPo4kViegO47J>Yin6rNY+x#9Ov7$c=RcIMdGRJurNjnnRhmB5$o4x<$N$R}%` zmQ*4~-J6FBxd5K0{{YuX63G-oWsG^dj@|oP3A>yhLyZ3bIwg1-=4s}VD~n`CV6Tiu zpyWB{u1#+gEU`%NN~Kv_P>q~nmptuaG4wd^(~7UQGc1$FQZ$X1Y)*F` zD?q{v2`*-Eh*U>tkrmuAoR%j8sKCdswMHR@q1we|ou**2MEjMGQ<8d+PB{Mn>(*TE zNak{6lFcXB=ef4ExWtXPGq%vc9Doss0li7~&q|5%=Gh5(WRG{4ZKN1jM_-s^1IWj( zz6~YBQL>n>jmf%1SmBgR%8JDDSw{>AJ@M*#REutHv1x1N+rw|RC&XvURRbR`(lR~9 zYd0%0Qn?J5S5nUaceR=yEp{!Xh=xo9$C!VKfWXgk3Hn%^n5E%^Ngc`CBH%93$j@J= zAB9T=y^NPIEKHgHA;YEQKR+8s4gP9vVbIAZ_6x0LGhDg{jh%Vb(f=`^sug&~C_s1NX6kji-=04k=?;qqyAJbqd~4AO&W@!TdccT2hy~bW2!j%NFxA z<=~zOp|~Wp(A&&eRfjuOjtR%9skaM-D+y@>mV8MNjg^mHa0wXfc*#Ddt6QvBaH)WK zGRE6pW^C?mdj7pCTc?E?Cbf=3G)T#YpK9(T25f+Gq-2Hqb5YChSSi8@=wHROY|_Ng zw5tnTB3NT8>3D|>wt_~DSNK)2^5wC}=dL)&sv$&jMKZ$cA|Ws4 zWQ>wee%S3+tx{KsV~;M8+%$x?0;_#`kwad5ZQ$!rI!5#mEX9J-gs~e~n4D-6Rb#W|<;i zl;Ksu`t!w2ZwaY zKnGl&_^OfJ$YXVcxL3|qmx#asXXsC_Jk^LUZ5n^FNMU9G?E3p4Aze6D(}!>?Er0MVa|K{;161|Wb@;> z5wr?7VN`-vO!YbH7#@TA)^Ltjc!^kJNFz@*<6^uHdE8Gpq@&JP7+2}#lj-@? zt*5jpdm=n){%dZLX8BhgHk^@+=a79X7QDw5c2R~aTWg4#We*flA3EAO$C)+`2+tu{ zo|)qqIOm!zaSfEFTWCuO44Jn85=l7DM{p`@c%DfoX^pZlLeiL6VWc=2Er44Cih>(F zyzFIE+aTLAuHr{t_#ET^0Iyd{GUjJgWR~Rch%T3H#BCgiRC&s!i#~JDwsFt5u{AZy z-Za-{8RU{lrOnrnRzk_R9FjpJ<{d{o`_kF$pZiR#5>922R?vO8TkT%#&U4rv2XZ;3 zxr!gNTnVEhN5*D_%CT=|2ldT%MWl?XOPP+E0I0KlnQmibZRObFGwYB?LxMB;R4l9_ zNcPDy%O~$-QBB6~I!s$33&`diAT!e4jofkxj~BghS=pxyN3f zy?rVwMlwLHW>YQ}MYZy$bjEIyTXGd}c;w_B2Ot}KTI5x zf$Q&9Wtx5KBgR~?Z#oPHQhvF?_0RtRuA3~P+0i0=LXofmMiozC+t;lqLE6RhIKdU6 zX`@*uxP~@(K=WXVK--r*fJpVnCZ#Zy-13O6#IdVO1d#@l%Q#?E{{RknzQv~UVuVX^=d+m9G!iESp649r z>Bm~lm6ay9)S3}!zsg2ago}rwqk}`WRK5pE=P`QiCLO6llOhI*!1HS zOJmx!w$dn?RzJOD!z#8g2qXFb07|M_Cdq|~uFb#NBbpzy$1!55l39w#4(>n{_q3Yf zo+Ks+Jhdg5?q+ObCm+k+twjv*PYmB`j4MXzG)gxRK>Ngw2st2No`k zl~tf{L37i2#t$B&@vccp+{Mx+j$26M@&t_1$agzBoNmWCKHk+?ZqaQX2w=jOR+v0t zi(vK7ZgEl|wOGJqkU=`h4i_rQPgdMMZ>Bk^LanR|C{^>Mi)bthVCVclrCeV(Lt1f+ zSxyy~e7|qZ7NyHT-d^BOTyw!4Gfxe0lYstAvrK;UVC~0m$RE<8y1coWLdGS$5y`P2 zMG8RAMIE#0>sGY;M4n@D33g(uvNQy-kp86ht(;=h(C&<4mB1O|X{NY{NRdIcQAXF1 zPf$4E{b>6{Om5*&vJ(_$$2}_5 znA90s;k4_SAd)?|7gq6xw}g(Ql5#n~&$!POO5WjP^2)`qvIdnyXL9;<9=(04DZ{L# zt>bY74ZcNQfmq`tXOW&cSFTktcZLfyNR=P!uWa)0%v@p`exCaO-LUqLNr5bA#8W zdHm}tkc=g%7ybIoS&I)cn>~giO;>iSU!^^c*PpW-M;PfZfqP$jyDZnlxl$?m! zl&|6rM_Q=Ud6-e=y~maeq#eM=oVPBtI zFE|+Vt1m3q6G`OSJG7DpSVSN*w{Mhi3H1GHpV?#I3kdNin#<-W>Uk&lzM`z6-rC3~ zkna-2*o;a`VB`aipp4e=+{sg-QsRGZ@*K59>cah>A77ACd}9tc%nfl zm@*uu*}{yT0cGT{#z$^(=~73!apXxNvm}L`06UnUPTrk;D%8(!3Qro&TIS>hW94O5 zG4IfJ`t#{j5#+VHjzzzQdv|5~eZ02&t`&~~gM)yijPf(VtooWMxb-#NJgcS+5w}~Y zL3ChF-VOlI=gxTg)eB(+0UC6-nJ%YgQ7~emfH-fIf_C*CdUQQ1Nv_BjF}~>~F_uyY z1yrAxj=ix{K`aqKl1h&hk>hM@5oX$Z@y~JEx1;J@=gf@h+UDU>NWg+3 zJ@bm)-sd%$UN5uWsCjPUS)x+8mfBsaI*fd{@6;MuWt@GSOrCu6kg6n7+z#aaBl4>k zD|2j2bA{NbtrT&enPVr8DPxtql$nsMG3WRDg0OsyU=VV+&QD?otz9XmX$a^fDVw=& zCP1Rqc}D@ZXq>v)@1A zQ4NAkvcoL!$TJ|f7-ksg8yHsiKK_-@O+I2_3$cjSk9%y9$2=s!(gnGgNUFem*lYlx z_Fqm0aZ+3amSx(ITc0TTziGdTgDU4O@{x?-kf)px-kT{ANcO{EAgZgkAy=>U?OB(w zUc#{5NvB;w1lJ86yz<%kkX;eU*uy(n4$@Cx-LqW^EZW?jMxFK0nk%R-9@t7CQEzK+ z2#t$lKo@!zj{K&I`a@`A&$7i%xftsn#GpIVYThqnFfkf^+#MDy?isVAm-o-@>r zm3m?1Te>Hfw<1rS6qC1}zfXEOUCjNh%*(d5wwEwmJE_OoKF)HcPMPC8sU&Bh$*9H9 zx!RG9&Jf1ZhdY%|2cE~M;-ZQeBHb)yiwu711pp`qH~^e`RhvmCx|&&|w`+TKc_fD3 z?lf7Ia&TCwJ#YvaIM38mX)dP9q?#mHRxdI}+I*jssXPVfTRx+&zj}>hdmxa)B)SqT zn~M>+@zmo3pF!(V*);N*q?i}nS(Gyak~lg400UCrMJ0;~TG{RHSSvD=U>!~{$2tBS z4EkcHsm)UHY*-|UD2%sT!b&#B0CE|9ha7jRbIZO6ZXv<*T1c{t7;jU^&#f$I>*h+J z=k1EyWtVmvzA}1tz!?0gvO^e{yT|k6aYy^0=Z-Uu{QB1B_*S`zV3+Kw!bw%y>9%<> zx6GsK&OHVxuOznYu$yS47WsKDyzY*| z5R=o9*C(enJF7AhrZA}j$01x6X&brjzyaHV-m<99y0TG1K_f_JW4;!3EgDOW&5^^9 zI3R)#e4zox89yxyDCoi1{U&Sj>T9bMrU=w0*ELaqfBkw6?EzGfxxT&WynMFK7y}3`p9i zB;+ZdU6jD6e@>;cbOqa*GU z$uknEB9u+PFjLb5^{3A?Zc8kqX~9QO0cIU@_*Saz9P_5rEL=#%WNpkEMJ7@h=O5?2 zHffQAz8WSG29h!l3)uY#4m~w~XS}Ga8$*Bv&@Bh=tNAWtVC+xhfRr zB;zNH_NwnS(;1*!t9P=FHQjk_7|uTq+2y3eFpOKrCQ%Bsq=B^H;1BVu zR?%R@SnMCX7YrM|I0SpsQAmk$kj71zouRlwvxWO8XiIr*&t86E(~qw_ijYj~0;DpR zX&cOB$IagZKaE$7fb;Fke)MIRq22V&TNYO_z|#N(LHoXavfkKQY0S@Ubpw-d*%$~^ ze5?W8mcYh&&H=)wHOh@g7Kt7K`^OUpj$|KsKyOTR?fohxn%*mzUL`3U5wa^NDyJL( zI}y)n%@2EX7n))=^0W+KGRK30I5@~SJRaYzG+o`zV`KLBU?FBmqL>gNjky6-{m@vk z$Eh?@Q@*ElI?Cp#xrOF3$pCY88!T+d3#$Xp*8Uv&3RzwmKzU)zu}G@{V}@b;T|bpp zEd{U6R@m%2N>3{!V|GDogPei$0np$B)~@+cOCY_CR632ak_ZHJ&mH?#{HUs&vgktp z0A_!+qRFsr`LGK#Y7STebHU@KHXD_mK#>@uSti=d`6X2U01*S64{Vy6NX!o{^oR^I zI>!Sfzzm+CCU+13$vrt7tIQYkXWm>7aqF@mK?`UA%_D@5d*_lf6y#RI>WY!~N} zGz?gdgXm3Da|2vTkz2VF?cT%?%zaPcQ-_`#PbX<_EjNR|BPTf?ynFjq04?F1#cO>O z%B6^ytN!jnH!$45ZUZ>N<;%(t^?!>5SBN*5(v+cuY3}H&z+i&5@9K$5GRoNS5hB$ciL{IAsi^l~dgD z#ttedC6y%>uIVP`e6Y(iG57s3Tc>E6%JweZ&u-pNmlv5Sw>u+f*sBhl5ry5B&pmO_ z)q=3wK+M-eNi!syBzaHnn$q3gLvJ7uLJ4MUuNfx*lfW4rKD7^!g5|DCk2dBr=Cgdv ztKSDabKZ+4jn;LLJ;`P*46xknRg;|V;N);dJ$da{gdb^ZSmJ2+v{HGINhnoN4?i*E zBL@S$C1!5q;}bsW6kBD6IYbk@?e=#`K2kRH+A*Glo_{Ki6=e*A%!$?44w%jdZ^UGA z>sHswhT=u?yzjHhaKiz7vT{yOLOKj)qrAEXSr$OXNaOkT+o~qsgQo|KWcN8Itu$cU zWr*~{awITW++SZ@=gG6PkdoetppY_8bImphE#}@{7@%uyqD_ujL0&mNpz%nOMPmUo zE!-bzCDhwmnLbm%1mp$hA2IFPpX9-F2xf##%063}2m>F`=buU&NY)N2C1wWJJE@^| zMa+!k3~nSG{{TTvlJ3#0{?zhF%LpGLz**UI-9}D%=qh;am@%@sSY(Zgu?FQ^lgQyt z;e&(79jdb-vbvA#%^F89%G0qWRBpp(89ZYL9`#X+Y}%T;XOY`1cb3f!vH8TSBc|=3 zvXg_3gp8g~t!CU$v(LAYWR@43Gsp=H4teSCR4wnF8bfIT4=YHJTf|4n$@y0&9eq!3 zX_gX1vdQ+~;c^*TQ@Om%@&?`xc|89BI`Ui`o`}~GQ}>3Q{mO`n;K1$&mlUz>EKfg( z<1~gj??gnqm~s2Vz$(ChTvm$Os|i%eEYPz^^2|UYILYCdoSbwVdXCi^xv{pE0K!7d zxO{xfxykFE+;RT^*R54vRj%bmtTZ$2r4ut3o5_v|7k`-FTsP=>t+-a%lHg5tRUr&o z^M+};-ImWB=La2!9EzhYw4{>@sS=SQTeE)dH7BN9Cyv0Lc=gRbV=F+*6}Xmgr_8vG zGr4^S>6+Fx6-3Nxa>`83zy0*F&aA~e!jT{xwtN2opIWmVP+6;a*MWmD+2$M;IOKh5 zD^~O8vxZn4uPQbT#5Z%)ZsPy}Rwh_g3_fhnEVp}Xr&|>fwYc56q#=n`7)}Q4<+d-DjwpgF>u6a#CtpQ>6MSFBurjRBX z{{ZEwX9TGyBOasQ+up3mtfWO8(?Vwr=1U4G1P;WIewAtGf;GHs-|EJ4PCEj4 z>(3p1d7YrTxwHW;H%}6~!kc=Uc85tuVy`Ay$sQ2ge zra>GKqfO>W!fBTtWQB>z>FZIfvpf|$Zy^-B^ow3!A1%nWl3V)lyH(j!xhg9Qx;sR1PlEV=LUm z*7B9!#xfQ*Cz5)TfO#X{r@L#*n>#6<iK9!u+n-%IlgC}Y6Be^YXmiR#rEuMHBj=$qX@~R14b0}3(v4BHy z+v;j{h$Qe!6pwRiTr;6jv1A-$1Md#}_cUBsO0p`&G;0fP`Pm6)1e|ov59xtYmZDIV z$S#uGQI09p%MprIXvn|}NI4#-9*5W3q*)|XU6IK!k;Wc218DUik;g&Day{wEYJSlT zm?*KVEYnKTDvXYBGmd}y)T|L?w}hRG&Q*p9J+L##$23B%+d5#IEZa=wOjAhmT`Z@} zlrSYnUB^9h(~jrsNi3H3jVraw!4%-OW{4C0GvL{qQQJZyl}FfxwapmDU`M ztle?OdgGowDtm!FpprI*Pcev+0?K(p0UrF0e;<+ydtcFiGw+QpY#iA`+OTSmyiwZewiYjtI_2 zB(qxsmYzC0Ann%5lo%;~f`iOBJ|d^6;n_fS|TA<2V5QDCbe?bJU}2klaN)Uv0U!n&#dc6x%h;p#@`%kDD#X z+Cd{e^$oo7EJXwcW4r*;f>Mm}MT@yBj>sGcZO z&bPCc;`x>Ew-<0MZ?uf`1dqtmm&}m3juR|{17vJB5$#BfklRZ;Mz+^5$sBQ{`&IWa z`955dK?A7v&rw>YxklZkxn>V6B#9bGvdrz~ZzN=YQ(V1DtBTxX6uw>3Mp&e6(w2m-4a0Aj}^0KG`+N%tPKr#Uu=Zam&( zQf{28GnexV1^)necjF)D=~B-MBC~y!Lywx{$dhz_U_61{zNh-rKGP;RBu6lBJ=Fna z9-w;E5WH%Cc5j4Ht1NR(x;dm%(WFtF5<3nnNshKL!WAbM7M2=Jg3ZwKrpHXUV4^15J4OP>U}BkJY!NPX+p|8 z#F(AYgVdkP)7F}kZ(k{`t}VR4{{TJIh{iw<3^tR1agYx@oQjw$rbgSA#Bs?KYR|eY z>-(+8YbgFkt1M`4BuL|Uiw0jQSnx7<$t3hW>Mb~vBijDxq5;$q<%7WK_*5$t#`S~T zM{#fqp68s_(M=(w(|VVDt9V<;0!Wr0FO+d1RvmdGrhUCWwG=Wu zR}sw|QHdZdcepYcn373g*%|GD#sKe{Si~|l(>R-H3O90G5&kBnwVu?fLa6h~Rf%$b zV8f5rrB3WF>{Pi#lHtHE424|^Ic5ZooOaD#xUq^iNuKd;SM2K1wSY0Fm`5R%fF!8M zKCRA90X1N|NJ2{#aYzrD`^0U|TO=LaoDgy`+Z{No67F;os|IPHIgQTHy*c&BqngXik0wNrpCudS^4B0>V;IR9=hXXDxJ8aGGJBFW#49w4 zEtQvN?`~X`!)LG@d*ss@WDchBBz1~i=vokW5y&KT=A33$jZ)eaGCYgDnMnQTFi3mUY+ z(nBWYh({*nz$ZEMIR}bGy->)VH#hpkUI@=l{?xjJvQFyo$fL}NZV4Kw4V(;Pu19`3 z&(zvV#%;;Sel4NEDH`l%VEYG{bJS<9J-T)Ep{*Wpw|4U^OD51zHW`m%S2^k4kF!rL ztoHL-Tp1QVVYrNmy@>P&sQQXSYXmLkf>pMz9H1*61`oD=wXHjH?oOgWrpa#0c`W-` zhSl5ar)- zah=4ULqzQi@rX0>uhLY=xU_ zyO_3j9!Nb0x1|QkFkMA3!5yr3cKVDr5XUa(YgQ~{kPPi1fE{uUGmpsC4YNoilogE& zWrL8p&j*|Wao3(dTGEDTyrSyTxH1^o{_Ai)W;nnq+3oZ+lF1CoF_By6MFoiYQ~}s} z_s@R)DW!P?xmw(UJ&`<{rIvELaGSQ4kNGJ+{{YgYw^+Q@Y3GVz5Gy1>ia1`xkO1dB zN1>==moZ0a=6Mmg3{U}vb;tz$0mrsauQ0=HEDFOZab_mm=%_rx#PjnUoOHnLiqXKu z#WrhPx+?BT7C6Q;B-tW1Cj&U-jB-y}t+qyWj!8^`4(~D~ATSx@w*>n7)NH~yWLI6& z+)B6@#^ug)&PZTAI^(riRCiALli_X_s&j1;~a6# zO&i@5k=2B7L$#9JE>sNk!Q!qlnq)X7Vy(;&M*uHyP2$QP3njc^B*c^QFJpj7!60$$ zDjCebxi|{)KbIN=!$Q4sc{v!s;;qGVDVAAdNR}u9>|q!zs;8e}&m2@YamzoD&Z>}Q znm~Y-b;%qN(Ek8ITk|7m%GMScp}4Yz8AxF?f?qMiZs#7vXBhyV{?%!&8VQueZ#Bb9 z8!f%Hs8(qouo)xfBx9{dYp26?CA@GvXkI`>R~U*o*?wT`&B0PQ80R%?ua+ms1*3== z{FV|&8P7OxOyFnV^Uckd?z1t0%RS*jC6!n)Zev_@^vBovRk%Z;kWG|uRiQ}}4YZ7@ z$DtgLYR_SG_bV#HGesI4$Ozjf`#*<#`qi@>{z+^npXRpR+zp^-AN_CftfhN1Tcm{F zBTDNlFU+T$XDyz2s{$2gOe`_5R{sDniITcaW+zur`g&eBNdsW~L|>IQfN+Mx69 zOS?amBU~(D7j9Jb=sM%`^`#c}_i#vU{K%Rp%zj(jn7~opbB}I7^{JLKwmWHA*Y__V za-o63l7AuY;RrLHS!o8>k(lp}T9 z#}!7xY2kG)k+hN9?MR>IjZW;24+LcTeQIc2AN2HQBF%Y?AN%dRlTZ*DoqrCgD2BD77H!Pe(@nkJ7j5&+2! zfCoOF;+rcj3^J=MsNs|#1Tj9Rule?=wF{{vXszWlNcO0|Jkx_77;q7A2qOfOoN_5@ zVNz{9%E`7Eq>IVgF1bsXXB~PHJSfPHDEN#>A5RW^gUZpYy3?5k0^9 zI7Kot{h_miyBNv*KbN&{$r7%U*d9sQqM8z>J6RQE+(;V^K|kl))}+Z2Neer?sN3T6 z8|C9Bsw)tYL|r6lCNZk2?P78ILWh;z*UIpUSsIXEFsOvmfEdU-D`gWmw{o;M~jd zx0VTBfP<0T4tOZ*Cc}wMQw_>Vmoo} zJ!)l}PxBJ)IBpUzEla@DgCTF?!NA5&NCa>(*BPp5aW?5pi}JLQhmA?xLk`3I{{UKf zSYVcAk|_ymd_;`h8?pUsDM3iWbh%dLxSQ<~?kp5W7{m(JJ{A99DdjI+Nzz@?JcWy4q=6Kv^aOIlp~>!jt6TD= zp)-<`Au+&U4v!446NY!&mD|&wUT{AVS0S}~C>56$hKhZyPoY6OP_B6*0(k7c*rbp-j*jP6#>0Y23`Tm7KV6oYjBU{wpo z<|8;Cg*i17&`l_8S7@ddd+~Zgi7?UJk1UR$ZR3NUx$n}g-b?m)mfbCO8-lURG1}3| zj5Z?ftOx|K>IfY(P|p}!VdY8;u$~z?VIF#aAWyb?Rrp_b*^$5oK+GA}BscWPu1b-jOV6yl(amgp^ymC*B@;O(*plMK9WDfDVwDiOG|~;S0B}G)yk`d)?V5^Il)MUO zgu|V?e7(dD+~@VH&`obVQY%g-^5Y+M_b`0@J7SqFrLnkK;)fRm6C;e~L+|?S*;1BCi?3r9!+pAod-{kTenH#z;dN4T$JXH4Z zwYA&+?g`<@Qx(E)5wQg1`hmwD+~+iMIH9XCp`PXBR1t^-yfDt@BBuLe+dFx&`NAkp zQZjjLcInPr`BUI%9u}Gq5n0rQWh=H$9?GOWU}sW$*oi*G>^ z-OKs7nnavs;f=7$!=7`2?Vi1TYSUXYz1*eEn4L=`aLmd)zToH7WMKaQTADK*(&ETG zuEla1KP;9!cFuVJ01tX>&k)8)VzIBvhzo27k^cbethw*dN;Z&yd1)IdG6f2$86}h` zJoY`$N=WT3tvALQQ_W>q?ShT0y-p82jsO63C-JZ3!q)HvX_8AzlOq<8V8@-?ap{cp z^&L9YSCc-cD@-DW#mvfJhT2ACL_L8yIPK0)y;LTZ#+CY);DxPLSW8C7%?%pFcwet4 zaK$p-NnTr+?h<<-a;ma8-1!HlJ2LZ+LsP?Ok;1T)D>4Iurvq=dda-2`l3WX61QzB; zD|seEG>6wb^MD3NU@DrHx{fQF=SQPyc2U~JDyNq-w&&;XHaPrv9c$8ULtE+c7f5*v zg_IB&6GN7Al*w1WkN(>BmR$pelt>s^Wuv|4#Yhqs6-g^^C>VCVYQ5wkI? zS~1X-rnO~N3a=EA{J@iylhAd@$9k=AY!w3pw|^^l?$~9ZVt8zfap*lqHB`c_dbaT0 zi9vPwVGPW!c-xO%+}l4)cD7Ff`37!9{*KEI6$Ng61{opr{e<>n^}q^abCoObrbaN386G8Ppm^9N-l z6O|tS08&3n(h|>bgh&G_4zEWIlQtSm}9T|om#k}E?iw$=@vG0(5AX~uSAQG#!n zV#^Z5vi+Qye8t|1cJ9vvnw73WhGm5edy6zc1B~_`N?TA~+04=pF=jq#CvaozeKX#q zH`b^Md2G@|M&$q~8UFx1s@+$8h>}X>8E&owcIh-RvW=^rZ~^3x^XO`$+zWZ8GD?f{ zvaHD=ZIJgQjN_@`XQ$y>_o*DAoFYXM#pYxoRr-BLy=Kp7%vZ~g?GH`yijL?`1v@Yp0Zuvg*XYs5S=JC5asbSLgGnaO_nRbYn zZd1=w=z4u>r`UA+V6)po#{qoEr684)o!I{J^gTGvJ7n{6-ap$F9&PXdJhs>sn2%g> zpIlX=s?KgEfg)HN??mKfLY~+;JbV6h-O+xfLHFaKKgy(*@)%)K zjIp6(xpTHPz~dS02NgzGq`MQq#i9!gWD(9=Jmc7oYnr@ENN*YR@o@0QrCuw$hi%S# z;FFAX0B|~ULRUHFtjkw=uiL}6*r9=A1uf!o%eZhrK7-z|H9Hxu)h=MunJs+g*>H#V zD%=v8B$7bK2R&;_D4y@_7Z9D3#>%XbMk5WzJ75!z3GdE%Cbdf?svopFIgv-1Y-Gs| z>-pBPw<^@qI~;rI3nNP$!^&3M=5lZ`{{ZW&b7<)q5S0ZyovQ7Ok)E}&E%13+W=SKB z_W8Euj@etYan}Iwea%vrTaMc0T1#;27a2eqW6A6E&-v!EdLo>r&TMGn-tO5(5u})? zS-2&+KAiE-;aaaB+2d!KS)z#Un&bch`rw0{S4K74IO3L4Qdt=chXr=27~m7YKVN>; z%-_fw8A`d884HqtgxlXFjBpQrywyT;K$PXW5od_oTp*0eYHiv{WY}4hWNr5YCmGKf z{40>VzGson1*R4y#4!|sbzmLuB9LASwm-j3OHp}2Lums?_934Izw`jNpT!eyo6fXTsui5 zl65;zeuRbW2emmik;N%A%`2OTre}dwqm_2P#*tZ=+yfKE8=?Nch2kD0oR zxx9t4)Wl5^gLLv*PReJQ!y^Dj+(rk;K_@3CJaorB0oI;d(G*i$8+Ca6yK7=L^}E)%xweYtNbNkO*#l(xhxoF2^(P-+#yNF^7RPaHsFN7ue1#yK z@_UiTzCRkLrnyLCnn)&hUW_5{SBu0yYlh5+4 z<0(5FX~jvGZgtCLLmacIMckyh0a=e6dWz~aYn?vg+8B{mIAuAI1lqfR#~(mPCcKEn z6GB5Mo(5s|b0XvSig$PJydQ40v14>$Wrpc)0cjP3+rAHy*~lHi_Z6+(jT?_C>Z@gK z8oE1`LAwQhQdjy@>~SpOSj=eUNRBY1?ap!UTt$wlaEE)z=jKMlXK7%ZjAI~z2nXi% z9<|b~!?3n6C?CIOl1BlhVn8LCfEfhv0N{IPCU+q2*GQga%&%_pTgEpeZXA>AkVrZ9 z^fgLt8sbL{1XE@OA0|qvX3zA`=~Y)+dpRL;5ti;nXp$8pYYskc-1Y{&BTBkk`(ZBi z^FQUHFFiBkME~SLSEzD;# z+r-33vE$@s7yt$#fWbd>`&XGw;vG`nQ9RL29Cs13mUkjnIXti@AfJ9~r;Ekwd1(v@ zBiPCqHS@s1w=f(j+%bdDp13@6D>W4)bShGei8M_b;@aScF-L5y%n{>0cbT4kZgRNo z+Pxc3Eq*pL1!SE>LD{!6gT~M}IraKiAr__flN2!zoI2%z+@*W}07_)7c%+ZD5e!V< zXGJF}xz0YBCXP;7Zf|*AXnPHh0MGgJlRd4sHTf2~k|A+!;I260;EQn27Cl#nG6 zNT9N>P<^^_R;0aK%W&RblA=G|N%mn274u65>338HK9OG!I6SQ7Xk;lq_ z$>pxzbB63kVOfVym+dAcToaEugMa|%^{u@@k>YpQF@dDurQDlGBvn8NKGR%~`YYsl8BE>-g!vK|-92Z8|T!_-v6bE2Kt@3qUd z1SUma-Stx2nDy=Ie+<;}=yN$27}(S8XI6(9C*M5wIjx;G2qOsrg#6O7`EyITx^?Z} zky_SwNgGE4MH`GV`I~ag#GHSHZOtdtnZc&)dG+^)?-_Unbtx_uC457YtM+jcfr!`T$p8*` zJ$X3Kdh0b8no}fE!q`~Xe47Re=b-PNIX&~&lU&{Dn%-tamPl53_NwR0U)3>Ec4}^n-~~%B}-s;#Y+{mW(R4KK_{2{sS;*DqoK|^ zj1n>KDmmj&fn$)pvVacKLk9299eAnbXAM<%bYOj!##@VK8g;eCu^f!CUj2<8<#WJQ zayJ0pfb;2Dx6w=-OnkH{Ic&VSk%`Aq)L?_b^!Kgy)7I+Yu`cL~{Qh9TQI5yzKb>>h zhMuvoc;k-~GKKPq5*&9lDBN__^eUe!^vG_b6FbQs_ZU;VvFXX*WJa-*O8QCnX;a?NN;NfEdz?aL6yzJJ4tZY;X7 zaZJUE8~9)_L&eI>$9&2p41C?s)_l6&)AMd%y| z=Yrkerte*svN*~amtjXdm|Rz$dq46+vaLWLM%gUKz>5PKS2w?_l!xr1wP z*4L2|t|BnD__h|^obmwYBdGe+mqy1?^UbH)UOzA7mV09hGM}h0H3F|QMiScBNQZV+>OCn`?EB)GJ(>iz#NBd@F7Q{{Rrc_pJ+6 zxweS}GTA`Ph2XfJ)Z8$T9P*^?BepoI7m_-0W>V~0$GIYKP#)z*;67o`2ZBdlb6Ov2 zXszsJC|Vppn-g=jy5~Ii>59L2>Xe<9rP8sOk~w5DPjMdMC`OMN=Oi9SraIIZ@{Ed+ z7V|K|Cp+*l`Stbns^)vCXZuCOlglpVR*!~P-JG#tbC7X>I5|1#SFEm9VJ^b0Bxek8 zcLm4tIR5}W@%Qhs9?dbSb8u~;M`3JMG8N&BXLfpWIR~dc^?KRnNW;$~mOwX3tphI+KIf^Z#<52rbis)kCjesr9_Qb$N_M!-#qun1KOEx@?1(KV$#UbNL}58YGWO8$D!b3*0ir?xe_E%VRyy2xEb6>{{XN2 z=7%erUP@aW*dMa+mIVVK!Q zcXE0VZ~z<}pGwY2R8Ceuec%o>shMHk9~D1+Y~NGBbsYlW+sSqIIIZsG+^cZM%#t-H z=3IkV660bg~%OA$8%g(sbzCIybErynAvvAkOMHu$UXl63g&T5KF8=7nshOg zTqM?~*QC~oQjYmAEp0CZ(QF&H+lC@VBO6%o zRI37eHHqo??j`RP$H| z{mfC58NnPDBkvBF9`z)q-Y1+{%N)g+c}W_ap1=XqzIi{^xJ!=_JeKUxvMg5535E@# zFwo!)%((ej42*N%CzDZ~Vlgza$0pC+GRj5)#(z(**19QP<}#ru-1GvC3ZY!fD=}$E zka0L294VjL%YnGPDm^X zBRu1bbRGGrE%ljx!)r7OSi9|HxP+3&sZf2gr@y5Yk%gKr-YvbMbY{5|xmC8ehQ!Gq zCz9`yupWq4q0#ak@uKpE+7bk0Wbyl^u%X9Q#*HZsu2x2jG^8D>!1W)_ zxgA&}n6`u!W0zTE2k!&N9mWlD&0OiExu$dagz||N3z!Dz)qI!Vozb^KM{c?2uO79` z>KjYO-)8$%meOW5P<*g^F~?jUN4_}XxAhxoBY_Ot))Nb2Rfujf05ZAYAnPQqSTmE*b@a|S>-blu-js-Wj3a2i%HB#NjlsKd?~n7E#nqs8vbTl{ zh~i6STZ@?y2JNF6T#>-+bMK5C8nluybtM^S&kEFZE2P|nEDIf>dG2SCRx)`fsq6-Q z_{Un}Z)~6K63G;9AVm!@U{y+}{vN}xTKYktTk&%yM0V~K6Znf9aydBv04BK2Z$`GW zg8?Di0x*#n5W9Ui#~IDeQI!72#LlUEL zEsXrxJPh)hj-KN8?e~^(-oXpTvsuW^0|h57wm=96Zy@a>J&$i#)U;QH?l11G#6SSi zTPmD|ZdY!3+D9Os#8*9k8?>33R#lhpBxh?JbKgAUy>i7#Z?Wl7NghL@+1^KXx0}pD zN!(l9OA%=Ismg+!@v14g%kqq*AQgJ7k zrZx?efB+}+70z5~(OR_96p}fv;{C`{R7TD=k?KJmkFTc{omk!Mb@I|k<5^6rX>T>O z5`CsH&f;Cnr#udx#Pg2cwNi5>yF6cJX=Awy8yF-C(f8bPaz|_qc@=i=ew%X?G1@i2 zcPn)(@f>mEuLK-}(;4U6CZfA$j?gB=xxaU2^Fn!K4vGND&&!OS=j&X`l8-=-BlIk# z>LIfc+nYIIg>YqzF(4d++ymbu9DX&`S?hNbNRhm7+?|6GTms9uk~#y)9eLyRuQ(BZ zWwdfjG>@`F_gJ$M?r5V)bv~Hz$g@5~Se34#`H4vm0_ToCzP0HKWovzFHK>Ycu5zYimns#0@Hyuh z9X|^4p9I?67B2)>EcWtlX(qRAtr*8UutDpO&(PPcY1e4>Z)$HvtOns`xPZ#a)3TB{ zz#||t5L+A*j<`EihQ3FgiLc8$MCPwxYXVXZCoti)nGv+HO3(iIXBaDMxz1%5qkz7Y``fOijXG_~TgH89CeEBDCe(3}cl;jR_ zc>Q`Lw@7YfiSFaK`BMNq1We%rZHx6C( zJucq$VT71tX%YjqV|OGd&n?HMbN)?pdgZ(Y?RHETYqtzf??4}QI*j!>J%R6Annm<8 zL25koS#654TgtnnnTXolfsUNvxa;1XtzIk)(MJF*(6WaS;Z`zv0Ox{wW9wSVah!J{ z^IYVHip_5>$fmlTWLA)>496K6-N_kVgO2CgsanHxadyflju;U$hl?y^1aXm)Kl;?m z<9RLYZ3mfv+hdb<(5sx1-oy-J=~3Ajh3(RtgC_ND%^5pG9-wqJ!sGAQQl)gyMzV&| z>PuvppEym0Mag2sXXPF9*0fX!jON~Jzq3Zo94166vL9T3hxD#rO1ou-c@jA0oRy8= za|t7lpzn@*p1gb4p;;uEvW7zUP+3_r+1W(Q!ZEn8RnHh^W;h*5C%tN^rjIsM+-6PT z_e*a+D~6Wg?4e(?+TG3PvgeXcMgp^L!j1sQu8P*-?91IK8hyRmh~b9H4BnudA z&JF>`JHAi`Pt&zkG}F+=r7mBHvu|=92@If56jI~LWaNzT*N^`IRcl@(uroz$ibEpp z24b;=&pZtLz-QCzQ%IJU={u_u$kH<_MyhZ#+o0)O{;6{D?!<=KoPg<&vK3{|rV0BpD1_{C%o9q8ySYx!AhZ<;+IOtcREOab~VyR}0F3{{S&4 zcsU%L@<%k})BudaXSrhXE-k_VA91^P_l9^L=hCQM&oj%t+9MAhbejMeQPkt1?tdRz zy9Cj{*~FU|Or!TgG8MY*Vn4jSzNWONQ8rAWB(^%6JEwuwK1D3K!xBgX{{Ywib6p*t zsTvn0l2Mh)rcN87=N*atD}#!{Q*@6jG#eaa?O;S2K6!4#Bb{{Z^yhn~vu-QsXmHNu}PTg zBT~8hr=iFnQb`!~uMnDO<+N9xduvtX3>e{zp5B=!^EGzPE2w9CSMpLNAG^1Qk1I)^hGO+vMSSe*0^gR#wR*_m4DQZ}{iB=!$ce`c7HhylWo<9Nf9ML$EGG{muc|mrEIRu}tOn0Ts0(lusOxu-D%m^$A z1m~gc`Bh27ky~;jx+YjaYiSioPcU(}g&6%hcdBa8ERQpWoTck;NSJOQ`V*1#%`M&5 z$fb@a+a~47Y%m@3RW1@JW(=1bZX7uZN&v7cKnl=5RIEXY#cDMh~NLZ99FzbPx**Pm)gEoVJRuYdAtv}Qz7tt4VXfnaICVIvMe!Qh-^o}CR#Biw209I;7lBgWuIG`6Bh z&Uxh&0Zx0bynl z6vQ^OMk4}1N$SU`2OI;_@uwxSw50ike)7p2Yz7JM>+M%)^BnP-Q!hgu)v<80EtGP{ zl(vUEHi3W-Oo8ZXwYjSY>4< zbvxihIabe7f6q#G*${=>w)W#`jy;5utat<5=lM`#FA2CRh|Lot#&WqC?c5x9t>YD8 z=$UCUnT=OJczI3ovadjXp7kBVOB9J5w*LUTQe!g0{$iG2LO4BokLyv#GEe5JK4lR} z<)J%v#=iYI>^kI9+6$RHmm=Y8WrbNJo+7z!>CO(}kWNP&Rx*bvjQP_vcO=NME2;!s ziC7V|9)ym+g=00aONW_XYc0uSlz_@X>BrYR{XHv9r-9)yvUz4qtYi!p>J3u~fgCZk zMPoo+rEtF}jApW_i#BP@~!EXykXufjX4=v>wB~+Y{aoil|KjBhb zT;IcS`^atXV4B#ipqf@K7&!+4NFavE0OV&G7&xe)SwllSP9%~u`|&sq$LczD>}un5 zhYF3z(2cC;wTy^lTj{QY5rR@T>V$qRP>&IfH!b+M|Jae1ts246mkq(uEv z+vjZ-!F2h&mN{eVJmaeCS3RdnSn&C5^PlPHRO`Ce;fl}3Zd`!?IHzm!mf9y&jIBiu z0&i7lFwxaJ?2IbBtxR_d)VY1_>`{AT6C}N{Im}elxx}J5`2a_Xub#&JVx+ZNQ`-aP zBmFPexp@Of#r{YGLoqS6XB%}`#R=InUcN?kwV3NK6+y~ZBf2IhAM?k#RzluM<^#S& z*tC=+FFY`xZoc<6*WKDRZ-{WG5yLXv$)rrtek_#2SBkjVLMZ3qkefWVS+iD8 zj>UtDq6l9s_oU@Pt$QtjMTw=lZ zPe^f4qz;wJF)yKC37jpKF$s3)S<~+;;cn4eGtHq|M=y|xdlhsXE3t1`^rpTN?s z@Qyo57m}+1c9_ELl2>l=REi}=$70v#RYv7A`C#cM9xAXbjC||GAh$qjZSujW)cdad z2iZz^zLZ;hW*DFyZ)F?^>ax?BBD6_67kJQ@fls$7yQw_UeK8ACa;zP5qrp--SB=RF6k0rR zXfx`rnR%G)p-(13TE^|lWM6yzouo~iobssD>EA-Dk_N{_C_^ChCR4hF^5W&g6$d-o zj9T1%Lys$Mq>ZciZird&q{qzVC{Ul*WI|>PXxu>OWrcwkx^{0bFwE{6{qXE!Vpt4L z3(Vp2J=MDqJV6hCz7Vcd{;ksV$tz8LvFe_zA9@{s^;;!E`^VAOwX7#42codNCNDcE z2r)j6dsj229Q+Gg`2=m8dW{Eawme~%*G#UUAFkd!$T%s=lwMTX8)=121Z@Y7)Hma* z%jG|iorcnAjw%&SSQSY>mFw%ZEwhG7k;+()4+_a>zrtfmpT(A~ZY(!S=SH7}Eu67qUpO(P;N}dSCjHAy} z`cj;4rFMkOje~IBVrARE?yE|$6jZH;04@hE)btm4+S~MQp8WjpBKhm&BN|Xp9d!Sp zCv?UrWtB7Cc%oT-HlXXxO{S>2&6pkuT))(Ezs>_m)(r9 zHkfmS{gDcm9N4#9^~*KMRDzhrvQ#9kBpZmt>$=y0d^aj$N{$_3Cv!-kbB$fLY|+J1TOef=yu3!>2fq|R6FdsNG}MM<7~$2W@8UP zks*0uo`{rOyx|`7nO9Ica(nD8RbG2mR?%gYcyj zJs0I5;IXb_Q`t#XOTR(4^$UjmykIfPSMFTF;?@by^Nt7{*{&u9B;e{jS_UCKIx<2% zKFE#SVVW;p@@uJtpmlil$xZuZ{=q-N)<9%t(&z`#q~rADd;1X!itXcNC)P*~`| zAz|MV5VvJOn*@(0(Z~O*HwJxk*}dI*@~EfR^~m|AM8z^%xB>4Ong5UH`|=~71Uq~R zd#0vP1jd|+Pw#2?%S^ST5=19Cc4|?J0DrX zE)78^|Kj$K2BPexdbEHXZ+5KjXDgm)aL!jTIHX#;O~!|> zr(@}MuwoFK#t`Ux;s>P)!oXGv?T6yrPcK`XQ&f%&JcVBnmj5kr~Dcf|p3vH$e@ zY>NV0kHE%2qsKpns8_=>m?rug1CGeUHlM<2&ziY>q>4zGO1G6B4;R9k~{KPV) zlS%b26N(A33x4u)bgGPcar-Y@+fNfS4ALUn^-SyDp-UdCoZKjGP52H>0bWGWiuZJp z^o)-=Y1RIzxGu8f#sC)EJEaOa@nDuZ7dr+`5q*uf^LrL}(93;lT*{VW3{S{oyISRA zrmj8*I1s9e_wZLGiu3rV7)(%QWWVdA9hcX{Z)dA~kxB&`IyzYDz8$y8{F0cwJAZxt zUVQnW`d3cyLd`IwkI^|IP#uq#CAFWAof>)DQ-m)5EX%!M;eL+r@t?T74|K59iOiuWW-`DVrk;T_I8+-igVOH(- zk7r|YoD6JwG+!tIq-SAYu;!F4iVEv9(>?xbh8MF7?E0iIYM%#6_Ktsrkz zo^Z+S{g>s~{X7&gLi);`vs>@YCk~Jg;WQe5&z)k8KG%^Idk@u+8v{br{;MdL^+%1& zgi&CrS}}!l=e=Ka$zZO}sh&gl%=+0)ZTD2qQPTeMV}u7Ra=^r4N|a@l$XkC{6wGPY z(%?Go7DOQV{)oYdOB!LV6x8tPso<|k8ZEA)V>QW39$6)WW+xmX!Xw5>7HG>I;Q9Or zO&SIq6Td4)dNL5TdD^kO))29T^(~K_tOHZ|Z@C5Y)0%9pAEdkYU*yg|q{(?LlhJKlR_%wieT74 zT{zG3CRoA%6jPID?v;DzRN1_KJqH^t__S@kz?Ne{xO+0?bd&fXlSv!ND^{g^&i-u2 z&7t=onfiNXF8G@blX(m&_HFhoVxdbs|Cd%EKaFt8-MV@>BMt52FrBi6v?2@lG+EC# z0e73bNEz0JyXl;Q5m-vqe|`-U-a6Ut-*&Qp+Ui}tDAmpyFW7umhri$!%0W<1&hDh| zmQ;8K22jqZG8tLc%{>evRdhIaLtj{`p8*)Qe@LMteRzv9l0Wu%**fHQYhA4flNpRZ zrilqv7A@;WaD!0dFqxUZ%8wq^<&>1G=jQaV!!;RZbGU}c*7}skLeyd`<8p5ez#$%K z1sv&yvaa(RUT@Aq2BZDJ?#T~awUl;~yzJ>#QM zjOSFi5mRaUth;X}WAYz4SVMnvlUndpsm5L*Zt+q&HHFz-C!W7uCJLU z%=Ma#WS)|A&d>Lj7sKozqW|WsQ#1wP_SaaFoKduF& zlB0zevX!%YsC(Njc-=y*zm~N<;XM5I3zU)g6df|$JUA0;V_a*6gE{%X!F`FX<=k<3 zEeKyHJ>kg@zc}hEV0l$}bEzUosgWL7K%b29*xYQ6yBdylmw}~oygUp35`QxoY22OPK`)N6ip#~*s zAF#1BC)vl=j&|9)gp`Qb4Wp!X^s6LNoL2m5tU1z4B?4hGc_p8QFHGNhU}@I%bhyYP z=v8l59a3^qBbsdTHE9%`t2R#k-rb!|m67xj^jvH*cmfbDU^dhy>w_sWYaMUmFue2~ z5V7lg2!F}5NbGdU9MAc3!ihSTIqD)l>uJT;D`9Rd!$C|7(>^5%{oRMW_)& zdBBdGt?~?SvA~ew02U%#|5FM`b}Ed5AqA;0e0ofPt()gaXT^qD1H`D`ExooJ%E

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

    H@c zZDWXpLve-HFvA>xf4n+p*Vd~#Tg5yIAI%aeUpf9#$CI26_~!%CpK%gFwA-XNG35NS zGbmn}IUMA51E=RoPni~|N-`(EE^b+*Z!%Ynd02w3(l9=}V<*2}^&B>jEIYD=Vs;z1 zWUPmv+BqW~Px#aW%n6if0UloUB=D?HCp?bW&#hdB6prO>mPw>3lF||ak~t*fjP&VQ zO2(>A#7za9YVv;b%`VE|asv;-k_&=f@qjT#VG0Nzcpkq@^Y~Tx20HSDj9PV zuICZR1dSeXfO*>7WM}K%w}f5pDW@hjSefL^Nb4LDKbEnvDpRoa7^qfI(?KgEiEZ4h zj@*ThBY-<{KOQ|P^4!NB^pDH|rX}ZR1TXtcdY(AQ_NUHOrY#D|9`L^@>dou;)jo0* zZMksDcTDlCT%^bqVuh48dF6rY>4EL(S*Ft-OA{n!<(W$&WtWkW&UoxkrCun_BdY-% z>G1P}iJRXg`fxR}-?Rb8k-<-NQ2>;5%v zPu;_C-b-7bExfsW)n$-pwh71Mj>@K`H^|O&Ag@0hJl$e=p}!+({G9 zECe#dXN*O{kQ5)6rhSk90IIX?;#MW(o6GYG`M!AsH#y@qI@-!#e#S6IAl-l%mHwmL zRmCpG7qL5}4L;#4i?Hr~0|(E(GyY97-sWhF779T-kNfbU|^mH`Sz%! zv_EEhxui0E*8|MjR19w9{{WsU)y13=*~0BD#^;Sxs>)T6lflUCk5B&qUXez1C(W^1 zGj%1(s@y9QK3RrBfsUB<807kcNgK;+I_&bKnPy+`c<@&6e9VIYlenL-dUG=g*eKc+4ijq zc%*mPBzpu*6gJh&jeu^Rjf`{<&R#~62&9G+zTPEsAzj(r$L@@r00;ML zO2ws)7hw~XxZA$yAz>7GIL};VvCq@ippn)HUon{CxZMTXY~0MG@KlahoE^iU&U?~F zAlvpx+^V}ON4yU&YMdb|IuYFWsg2t?Cl<+>r?&E-xJQ+Wi3>OZjAtYgJ7jV=9Amdy zw*?uo0>{30z*N8`fB+sk{e7uIItNv|SYAfu=O+R%a8DUH#!dxXk6>A#FSqw$!ylQ3 zdY*aqt$A6cIViMOhUz#Vc6E8~azK_x13dL3*RM*_ynnP?7Je9e zi&4AN{>wAMz#pClA0``e;~anv260IodU$quZW7!q$8_>L5UZRL+d(6o{uQJjGB8q$ zdx-NJllGQ^?mJ6n;@~M*%!eSZLCNC>2iC1xhif%v8BpWoX54pm9ChQ@>FZ66klfrs zCLk)&{h4PUcz=5z#HX(nBnSn|NwEWn%xK^pz!T3tp48l&N^MxU0d|Zq--ZR#CvNO< z>Co42rf3pQ5#%cvkjB#h#z^uB>GbvbdsRIjLyG!zM_FVhBHJ^953l+4uUFG_mACuz zPatwJ3m{dEy#XAb$JV+1vt~}BrpobJL1+8bhdxrr_rT8YYOguBxLcUZ#-dqOp5NwU zxkt)L^WG*9xX zuXaA18rG84jA~W?0CR@i-dJEVcy0!G_VueaO2~%5O_) z8t%*?S>)XQSwA`TKAdq*w6{eN?IaKZAcOOJb6Q|y*R3T5CS!MUw06)I60{NdnE73o za|QIzZ^ETwcA)auli1+x$E`_@q;)-Mr*PbQp0+!q-Bbn$MnM98x~=VoBQ zWb@mar#cmkA%!l1b<0U1R@{0J2d7;06%KJiQoAh0BW`3&g28e}p#K0r&a~B|Kf7`o zQoEP|gHUCn}2*_DEP+Y6pCAy* z+;h(dBo2SAdJ@KwtM1xaosQVkX=9G(xyCs@p4E|Y0J(7+f+Q{&$)3G(KmBx`jHySM z@~uG49O}xe8^D8eZ2%HFWOw7K?^t&i8p)bd3`XW@cCkp|+FiQxtOh@oNwgM+IS#F;g5u)hNgy%? z7VN`nw@h$39Zxx}r`4UJ3kZvOkTuj~f;_R1FfqZ;bDZNI^$qrzmk7;mu_G*-1BTnU z@L93R$6R8trixp6MU+xOeK2LjaYjHYI}Ctxo`SHcA9&g{smU(pyt6l+w=v7}Nw*1{ zg#h%$Sr_d&6U*fJk}y|=Z~<(>&I3a=9%dMQ+k~qqaCeOL?KmATBrqJq~;NRSmZ8XHPssB1%@?K1Y~vNx|rN z{=Su+G|eBHrahmy0T^Uuf$NV<9C41-bL|T@1OO)swR5}67~~IPa(VpgRaQ6H$Ca6p z+g#gAEO30W+-*mZu)q&M4@~qVb~RktOtYjdC}731LSO|P=e=y*PRP+)#tCNunqat9 zBh;Qfswmyd$mPsZDjlp22tKtktnOTFU|!kWjjbAFOuy+dp~sgeL5y|dobml?U$R|W z$Q%70UD5S250nA*#!sQ=^XEm`oj0QaBr>m@8Q!} zpnRtsa99q0zLn_L7q(H(jpRJHayxmF%?kpjoUCU!U`7wuj@hc$cW}!TPSNi3BV~^t zDOJzu&1~e-)dVYYY|je1(LuP0Gc+^#>w*{^#{+N&7{NUI1J}J?xpQUam`9jCglM}=S!i0&8nn`3q073To-2PZ#;S3J3F zV%n286IFXsJlAP%7%2*43Ic#S@sH1w`O!7tK^ZErwbA|I*b5KSgTUwT>0H(Q)W%6> zo_QMPNdwICle>3PN$O8I$^Ny?PvSEl+HRO!N@FAhxd=g!9Bvy)+@*OL!S(mv8lza! zl#$Th_?44#MJ>nLt#_@&vHZA=!3B$P!OlM#<}a`O`4U+-#*WMOc$tZ2Y<2CBdgI^g zSr;1o7b$Q)#|ymBscD;XxIGR4A%8L2u`V?jCxRFZu|yhV*(oP6k(`eC9=sFB6y?ll zsrd}m9^vJXTs&qe6}L11uI_m6*Pg!B=J%1Zypp_Z&@?-tECVw)J4Q3~{Qc{txYcd$ zniaN?$QIT{oLwl44Wl?4y5tT!l5hrVnAP=bbhWfLQUip`Cc%)+&N=))8o@=W8b&in z!@7zuF4^Nj0DF+zL_jk$bul9T!0w=01yC=n04omUNc>- zm7Euo2Dg-5plIFXh!w%cO7aIFOyk`Zshcv$mT%=-cLu$n~;2q>sxT+8DHU>z?3O=>@LHi?o z9lrRJ@rOWxY$pEAx76cgxPsI=tbvyqIKbx}dT@J+`m6p5W${*D8GJz+YD*>2(QhV< zPjJFTjkxH0VgB!6|$ns99+V;>|)R4go>@Ljido?D5>3 zQm6fq3O3eWXQ9G)7&z3g?LRNOQ~E3TE8zHi9q`{u(q@CqySLMkT30wburf)&Cj+4M z9-PD3wvQd0f;nPSzIYlH zj2xbfIT+)C+t}CTPwj0ym)rKOL! z@Y<_z?@s z`Paz46T7>DD_d2BD_i4y$~Oh$Ah)*wf1KCZz6P+8>f6k`yWJ}ytA6l;!#Utr%iG!F z5&dhA#d6Sne>3ZUf+?b_Z@LC+>zl%<9@5R%j1F>ho&|kb<4+s-PfGCh?9mu>gB7%b zTdATb?T|)XXO5s84hL?gz7_a?r`+9mg{-vek1iPYw9aHJw{~&?$lLY*0QJ||R^AD+ z)U>&N-2@k@aJythk!EMda(U;D{e^u!D(a-;bbloHiALD@>$>}oD1=Gp3D1&2HBZFm^_apZo`9|xV<7RkdXZnt#Lo*!A~B9BA!Y{LXZLHKqpumSyyAXJxpo?K z<7I0fg=D_P)SMwE+HU^<<~3$R{;gQx5<27FzpbD6CkO1y;Li{I zJJa2&2oIWyV2oaxggU^)>6|RBA$`d8FCn=2@LTWYs!+ zi{#(rf1Wpuybp8Xt!q)z?%|r!?@M=zMUpb0NC^j$2SPDi1UAhijU?(MF%BEf(G=Lt^>H7a{Z@v@A@j$q`V@5*M0oLKBITW*P&mQY6J9PmAkdHg*q07B_; z7;%Xt+|jUXW83koi2zO3k#3UVFy3}{g#`ZqN=cgH+9ZxbB)A2(IRT2Uc>e$z`PtT! zXVB_PZu@O6E$<>|OSxra%9R=K^7QRh+sYChs`9MN#bc2^RUOW1DOTcL%Pqo2HhtI6 z*C+fc8SW-&Qa!th+b-gy;GFdO)JCMD#0IgA*WVHrFib;TQS7`%i^{&2l$(=OWY%GaocO1k# zkrh{gKh`(WPCr`DlJ4qIXI3IXDf8Tbay=?|ZOy~VV7d7e z0%E`eHJeC?!9f#UO(cK_W{L)Djj1GA+E<@kb^ibw$0gcpi+FRni!9N|;kP%ar|oGV zF&&Q4Oy9nBB)2^UOt$`7$v(i&vhI0$2KA-XCnpl2Yo9S3A^!kJRc1xO`D$q7VLbE3 zqzP@Aq}l-T{ZHflYRa{^lW|if-aw6p6ncMJv?R4}G(xJOV`X5?x6CKEg+P+H zXPQ4POUxMqox=nC^rx#bw5=J$kmSk${uA1xXcATvhVtVZ0>D?C*062Je2UwRnX_>$ z${A8r9%-K^AQ~5bjR-x{ptJ=(@owU+TFBxBEg~qC{IQ(w82hW(DL%#Cy3OwMHqD3o^5p zXyrmbcY(?6>zaE?Rj2aR9c~cjLP=p!q_>ER8>&eR(yL)$8-_g(UY)95i0HB$6{K{I zPcT5MjJeAe_53N*Nwi9B@?lq1m50rN{{ZTy+!=E&=|ZF94CsAvlm7tLsON~qaX*m7 zmGm=`<@(wQ5%OhS~SrNTMlZJG{luAxG1k zRvah;s>ib>iFla?k9 zM~=`Wn@PxB#F9bdujyPj!Vd?wgW-!CO+8vmn;QWn(a$ob?lO5|HymUI9ZwbLciwf4 zoL3D1hTWuS@goAvqn}a%3+Pphualzl6*lc5wkZYH=wbHJpx^~l+=H}OO?3OaB+lL!*f_8(PgN%$G zgj80YH18;%v*i3ClHxM8OBGK2t)pK(&*$r2_!;8g2y1M&+6JLLoB4$#iZT{R$s;O9 zJvji6YWL6CTj4@@kH$@9dueRaK^${g*y^?<$fOnnF}TLl(1JO@$Tj-ks(1?DT(q)H zMmwEK&2HQKKG1|!wA?VkNC535WT_{TNUx!O0{+aJMW(qAh;+Dg`+GwnU6(cirfCN+ z`_gl_f${-?gX>;yClOAhdmkyBa5h>b6-#X&tJ1={3`E>+MkURM_Vzj$kE8!f`V4v^5e=4&I>4P zfyO?S`h{cg_rsAzr%9<<+fO>>QcFu=3VA(3Dy{%Iy4lV!5=X^ciEEG z?cUz)0!kPCYA6e|{s4Y;GT9_7R7Nu-P3NnB2|WPrex{xDGfQm>OtQ$bS;sW;G|@)x zvS6yP-GhI*vbDt*Q%hW47GTNX}JR@>mS+;E|E|dgI!$q`rBiVB3j&t-GS(bDj_3{xucF z!#%`>)VBLc78{muLr9}IT%2drj(dAlwI$Ho*rc{A&aleqXXm++;UwJ=Lm*%eR&ImX zbv*i350>$7h=Q@lJc^HuhB(3Jxc2`58q|#>wvOKRX1kK*<1IWFNQxsPj44y|40Dst zNgW3`nx3H)GDit$*Lq%x z=jnsj@U1O2_2jv^i419W?IzjVEDGfR08d)i*Py-9wK;UpH%(!49Fg5cHMCbHRah`7 zD*_PYaL95%BRD+sT5ZfR-N|r}M>^f#A2#VaDN%;cIL<~ray_fel2C0IIL@lM(ZwX| zb7dHdHa6chr3hALBOi!9{VSxE%$EuFWr1Y2fJowLmNjK=xX&y=8NjUj*=@zX_(75= zqg7c3ReJh^f8$+`jrv+dNkuMDfEd z+by)-S=#bvr@qiZKZR_`2!c40Cod(saAa|oZln*^s@h%K!)YYe*7s&P-9*M)#+gKl zK6V`fg54B!7|A%zW!}jn-y+&6h_Gok`I(Jl#&OB(+XVAd>|~CXn3vKho=IgUS#I}v zFvd>k@r;ssVCMj5x21I&UECUlwVlb4O!`#PM{l+uq()C8J$N8-&m*;R*|@sYR`H^@ zvPnphWf^E8Z08tklAsPj$s)GwFJWuQTIE3VFI(hDmKew$fN{v?wTxu93o9PEVI)^J z5*ZLQiiKl-6qO_M{{SMmoo7e4xM>B&q)>!aD<0s?t=A`^9E|f_9fZp)?_mY92&Vb0 zP)xDIAC^Hp^f*v(xyd*cjjtunjj1KfH&-REEu6`91MSOWX;ON8!z+)%s!Y!7oaVHM z<Z^RP09z3-g{LlLlSel7~`B{ zj)J;-d%<~wJ(zzj*Z1MtITdsB072?UIrRdl+`B#dqd;YY&-r$dxtDk2%?qAZJE*pq zk86J_TuBVqFh;DgMvTlC%wjoJ{{UzJen&wZ3?(ME&iDO93jM-^R zBP#%M033q6dxM{P+q}Bffik4gv<(ug#T>=5-1Cmaaxy=qTej4!e5Hcz+A%iL)9%9U z{w$uLiYh`jJkEK>M+bAGUPR6ITLLp8%`;wJGf0DW30w>nY?1-S2GQ$W^~Cb?4XjcL z9!6G?ahzwb<6hONX}0%rTL>kVZz(p!@kmbKdtn&?c!bm*>8r z9*oHu^Y3ge))m@^A3g!+XaSq4*faPu|`E^xedJx}F|^{6eau5Kc?P^cg+nPZD6v4O^T@wIOp4?+R*2~#Nicd|?GrREinf8%;9rP;%A+dRT364b# z+XE~*WcJ`^sIKowf@v(?3E*7KK|EuC zP6s}<-RZs)7ErwM8?~187t8xhhm-^5J2F&p+;#P-=5AXVsVnYbK8FmK@?L5d5NhIh z8H;L?NX#Z6?UWT@ccH_sc*=}|IH@hPaizVZM6k@W#M_u%qe;If?=E=HJ#k%4>A3qm z7G=>bNnbkQtwd%p+;UVFAP#xS>w)XcK^ThS=%u7Mo)agq0kz{W;#f$Lp~ zs~t4=M^kkN*yN5mA&ul#b!g(aM^@X^hf-9INd-v<-n{o*xBD&76G!I#vCD;yKtje2 zdh!9u;2P*gw3{{pRK|@Q5ugEtBy9%+rbc_$34d)Q%<$?yb)3pKTE}qgreWI{^<18K z!1l#);*?iI(4_};b5~Ecx@Ub-cM~`gL;I!)AXWr)=OC#dk?YS|==9GDnPu}{7l->s z4Wbr|F;Ua-$mi&N>zB~yhUO)9B^7UpFGOW%^_{6o||%Z_c-n` z`0DsaOq)%=yh&$cYv%4m3Kf*&fsWb!weMfqaUV80SA5=Ue*1pqCj?_YqP+Cl+SuLR zF}p%ROy)ovb7!0$O7V>L<2`G!(B*u{^Hpk-d!0?Ktk)YSj^*2IW6ZKCwq}fsHd{CW zf!l&Rn%!$;^E{~55ToXkY-4am z_K{tX5=TyOI0qRc9C2LJQ&MHANg1|QvLs6hLw7gL=DrjbUcht!`}F!(YiDXL%xerW zAOP=KV-8gI;N*Az06DIELU(VphmSI-`NEybFmuNpiRvq-YgYRZnVR;|Wsi%SXx3R4 zW#r&D3=d3kfPIB@QIxEQcWq4=#Hnu9%uIwY7cGWhGlS3oIjb;Ry2fso4*p))!vG4L z^X*yCn3yDsaeZ>u>XLt@M6t6e8O8zQ*9X?RNbp2_Geq;2RV&GCbm`NK;<^^HGMj29 zMf;>Tg;Ht!=8iq9!Z8U7DB(~}qvnhvw;oxwCPU^UFcPqA^dS8@bgn|?%0##*e8^yxoe+d(W^9lT8R~nUnf9xUqHw9X zNbC?K&@`dLDupb$1nnauj=zmt^H8VS3I~=Tt+kL5yLWo$G>C-zBNh|SbT=dsLI;^6 zWA3jboPo!B-hz0qV1a~E706kTFjA^G=ij&1hTCU#G?F#!o-3Pj(@*BfG>as$?c7WD zC+K^h>rqd3i*JAe!gm0|HeJoTpPP^mBLj|=HJnz_d6zITiY8B)Sx#8=+PM1UlkZbp zECp@jD6ImF?MDhsfb}E46>(Q(*~;V=lE)Bu9auc4cbdeVqdxho-`X%qD=Z40MX}4s z*xb$21OEW8SpH;-D-q=YgXKpXfgXc7{cA$r2yOtKf+BpPSi)@wp8o(^sl`Pc&VjPm zTh`6@EAC(%z(`)5_#BGUkIZR=Ko2f9W}UIYTycZjp8WOpsN%J=5;xd1%Plt20A!Zd z!*a)*@##AESge7jA~PRg1~Lfwj&sgH;~6lK3Mm&ZVOz(H#|^!O zv}$(~I|$nYCzj_p>Ha35-tpTkY>UgUl>G9%)add^BuAa5hDIeKeX3A@bx$03$0WsoQ`_-#Z}$43po@SAp1f5$~ zkU%_SAE#Y_t}3Bf%%9qPmq zx-eHl-et^tB*!Y=pO0Q?kr^Xr1hHb{$!?)oo~E?7ta4hyjSQqXH~=v+bNJ(d`P9nt z>NPD26GqS(QXef+>So%Ku#lC)TH) zcXKqR1&(2GTgrt?M;Rw10@*kR029xxLoBN(R@hc>S8zBW4_*)X&$UV=vd8Yq&J|=b zAyy2dDxUl(C z>k*KGCFm7>PBL-ytmO4Dl`nLXG9tm3&z2-(mEJNJ(NEXbk*%a;S5uh79n1mT6!sp6 zwtvQ?hCue}B#o5KGXPsTY-bqy)RH+(@J|z}G-(4J?@xAt8^iInI8R`&g|ci+eo6RgJvFbPBo8@U~8J zIp{qpJlw+sQT)>+?UZCEG5Qb2nrR_M$&skGRb%$p1jT+x4&cY>$Ky#jx0zvJ_>f1n zq`)UQ^cd<#=~e#J!_AFjAL#%qA1o51JwY6fd;b7Ru>_IFeUC0FQaB`6LZmA;I6M)^ z{d>}KiJ+>2R)XHvDdtI_jycG1(=%XhDnJ`aBa99+jMa}VQsf`D+FRYm&HJl}9hH=E z^KBh@923qBR!AkeVqmnD(NyB$0Rk^$*aMOH;-_Z<38E%7nn>{SV6gKCbL)Ck?8k_ZaIZaje^ zx&?+}xjEw_`k%t9qOz0?6DU+FNk4e{pMRwhyJSjD6s|WrJ9#N{Ew0lON%HP3k+(lV zo_Oh6KWB>D&3Pb5-5h@I2?32*U>tSaJ^T9grkDwNHn}luR*?wcFwf`5<;`8VmeNBJ zmhu=QF~+hp#&D<9t2~9afrei$Rw`U{`AF~lT>4emeA{_%1ZyO3 z_H!S~`%la=$Ni-vBadFaYQLKCB1SyMfk4{|t_I);$>$to3YM;g8ghu-MTYaHfe0Ym zq^e1ghhczu7|%H9YPgPDglCFWcaS+_EP!s16P~1G_26??+E{Ka(p5s(}t+qFlwa$+lP#&+Z~nvo>*%9P!U=@C{7S+sF&6NUta%^YY0U1pJ_{ zVmh9`OjhyPnO*Y=wyzM4ZcvwamP6%SD-hlHU}R*2@|+$=)UnYeRQ=||CVc#Zg$MN` z{{XL2BNAo<%7yP4S~%JqFo&*5Jcbwp7|9<@7!}wUSyYl6Y+ae_|O!)1vBjE)Woso90~FG~^`9LD6Tzzaj1?_<{o+njxAiyXxm zMI3WV8{|chMj1z3vG3a_si=Y&_n29+Ao+K$N&f%}h{`1!+j4n1!e9Wz@!PI_4Lh1a z#WqM<1~5Z(CbYT?JlhsfTg&T``NugJARP7Lgi~sza0;ZYw>;sEGzgKNK?HX2%G+U4 zlBx$d8Oa#wk4k>ad1N-iTp68YbSG%@6!3p8^!eS2b3-FQo7GlHp5{;9D@aKSPi*HL z@x??YDFBvI*)9Q9jPS>x@6);I*R?#xvKb?LkFrV(i*Gu?<}&vg85vT;kPol5T!C&E zZe{ZPwf*egUQ~nXIpF#pxvcrMF_XF@CQ?#n$yQDi0I4HALE!eNWr5TvR0U*pEZd0# zJmc4jbjIP?ToM50t;ky`ZmBe7K+l}wM#$^RfH^toRikDRO_VNo zP9idoH_6JW{^%V40H6N7GkS<(3vD!K&27@d31K9J3>F|95HK^-7~{QN2{dt*wz!_& zc;$7M%5uA-U{r(Z2qz=lRd8Q>+J5vXLeAw#Qb)f`^rYf-#+}k3a?zumrb*;GVjV)Z zdY@i0F`o523R+0i?g(RN50Xj2TpDC$7&W;2aZU_ zIXq^z)JVi5oxVbyiy{WYd-Vi+AL~SL%Mu$Pva*Slgg|Zt_RrHiW}}rC1ky2PLmY~2 zWMDkDX~csdu^j$KG_l>r;IUSU726!n>_}{qLB@FJf=9M}_a4^miDkDaVGPW&C|{I% z^NxCZ)_X>Z$gLj62siHJZm5=zU}-c{xVS}?ZRCl()*~hdEUMi)@wj{bH5J?}z!r6g zraZlvC9%*SOrAd~Ssi@y8baU&Qul?|Y>avUF`SO1^yFiZYDsP4Vgv4C8CR3vxBmdH zg?sF0D8&h}rfXy|{`Hl7!iRC(f1juS0Is6)P}|Bc(K(Fq9(L z=xtd+jgHwPAzI-SGcY}Wtyr4M^4>!=qMx!Sm-d&L)g;<;f)t#b_r`INlgQ0TE?HA- z&y4PANk24wxaTIWH`(Ws7lwJIw_8Lf zFjBH-86b7zjxkP9keh=S&2)ZP8cY%9XQ>^>UO4*HGqlkLR>W|yZ?hE2#@WFj9_4fX zb6M?n@}vEo^B@`mbo$-oD-eD*sQlF<8niy)_tuNcW_{{XGc+4ajS+01cSMP+d!u$?^8 z$8jA=z|KCHuRg!j8%^`ABNN}s>$l|?k(7?SU<1!=Rz9OW>`!lXZ25|5m1MgNcQ!uo z9k>UadWyxm+p5Z=?N4o)S!1~bg$%uO*NlY?HOMN;4qQqi_!Gl=;rY( zw&uz~H=OqYqY^Bj1X0Of!+>$$6+-L86W(eCCoe28M2#xPC{h6jslonVoq4y4e8@h< z9lh$K#>}(K4(0a1_v`t3S1D$G2K)vOK$>Qp+%92@39ZUikGn?Ou8DJ%!GhBsRm%Q6Oe%t;XRRoaY?i z_273E7MZNsOJ{9lw@VTkOqP+XK$TO&DQ~(8r%#ZkIH8_pq46`eEVt$yfP+(<(`%u6UX!by(}o^zb!bmF0p zRTJC9V0)V*4Vg0BETTqPHx>Zy=%n%NI&v#R;!H~f6KXL>=WMu+IIU70vVccibRhRV zuyfkHn!@PCG>}bxWqn5HDQ_8Q+BjPPFH@WVdUda$NlW2p$KyGnR@|p=d~a6c?RSBm zTlYtK3l?RYIc9b_+^4oV$}C?tWWLkLz#R?=C)=$};!BCH zbgLV<(%wsSwOGZx5bcqfatjs*0Q4BfdXjmqe*v`muD1o=lCs*|!=^NUXP#`cM#F2I zg#hqR9)}0kv{O)nX9VZ|&pBIP$ogW>#3^feC7MPqi$@9oELC6>YkVvj; z!aFWJOrrWxhBWUNRPES33D)xmm(N7)q&B3;7h#BUFS%WJP!?9on2|R##Iq%k> zi^C~%s7t8dODT?ccSR(O8_aRbek7dL4;X59_G<>4r)lu0RaLrs*#fYK?*>3e1dI>| zUY+q@O@o@8k@6V)Wl2Xls#-{P`GE^6=Oy?B%+qb#_QWF=UA;7p6RAdp55IpEh0_i{olClknSWRrBpM%)U24i}(1 zxhI_QUZ3FmgAJ1yp5o@<&E?M1lOr%VCAsBrNAQ3!dkXEZhK!)EvBiSSV}zQLTBGET z6lofdf;Fpe4(O(J^NTOrEjOxw%ZFU`95DnQ*#MAhr|{Q@qSNhvw6!vV^438z$>yYz zDsJUibAa8!!LIwo-VgCi{vx>5*3e6vptg~13^R^ZdiCqiTvs!1;BOl09(~58;oVn7 zwJxle62~6ff~U76kU#@C&Is>Zk(6OA&!fcWZ!^KD-Cw^^8^kL$n}~~9+e)%wWs$eE znK=aH^XLaoK9!Gc1X`K1iqhUeIFWp~Ze6^~i3uMn;d7J80QLu**P>bY0N&YV-r%z`Viv^+87$`g5 zF=;s3vHjIn3)81Y_8@d8B{c@ms>!f5G)HOTj~LuFrQ}x7DlNJdg_sr{V#-UAfe();Z%?PMd!A+m%5XEgKJRInO6KH8Y!b(EX!_^3P`o^!x65PP49Q zUK+AC)^`@y8m-LCe#rLTV=|F~Na@c`Gv7GC&&Pfy_?joZxVUTWI@?dUy=6#rTT^QU zDyRKgjFL8vGEREe)ptJzG>;L$C%B$@k_bd`&-Te9atI)fp!VmU-$PvOufhKS0C;Cn zWxLVrWYYYhw8?L_85obeM+b87bM074tu~d>`fdjWgoJwE<^E^P3Gp7wQTt5aY*tAm z+Z@jQSatgJHR~PT$=#~C=u+wOQBO+(_}gZd7is=dyg<^KR@ zw2{j8@no!O&4HY90X;M8&2~BlpZ$WS*3Cyd05w?Ic6G7ptxUA(CO0BC0?KmB^+{2k)I66iC;EShPr zkz`c9o)nTY`2PTwselzqd6P)qWw@lXFk#*+kBkgm=8M*mq zyqeY87^Wwa<)AE8bIt+idg8qwRMRc){5#kkb#{>QGC>Q;Do6lxk?B|To4*nKKEAiRpUaV^ zmO(wN@hbUhK)~AB83X?S)y+)s$u*(T>?$Rz^gHcod@rLov9yV%xd+TYYPpXQp#By4 zMnSKN$Q=Ti*~#WR}p}+sPw& zi9VW3so;hZ90AGT0(u_Cx=SlbJY60w?;#STNV8czpe2X|a6#*zP=7kgIB2;&4qEs) zKaJS?O()Z}jUou_?yZvU-s6`tgCCMXIVaeT+0P!F{L$kNh<+x&Y2%Abu}h0rQ5D^+ zin26lO8n8T6?bjPByK%P`LcX7#lAD~_rq&p4U>q{6B>H5>KAeRGwohqsrchl)nkKXlE-g! z<*lY~xZa>1d0x2sSCt$*X}c!b$ttpG`@E?8>f6QoMwM>>hfy=f1kL2g%mj`Hs9(C= zbQOobNM+etA{{Z#Z$bK5}Ec3}Nj0r4ju~zU+Y|A4t!4H#9C;3S0npaOHW9tr*t*MVEZ4CdE!;xmZBPjkMu z)n`k1C5pr((GtruC}|4kJn}~&MhB)cDwY2L#4jFe@^7<4YY|0R5mjSmjBpB~fH}rV z>U;CedQG*Jm4&1t=gBd}CfP|{+fGRJIRn)C(`T`bH^lwnm6Qz_mkTs)$pe)n9x>n6y$n7Z*&m!$%T;OKF=pVi zmd@HaMCE+)r_OSDT=vK3Sk}6QgmYYfX+dc!M=OVh>DWkGOzn_uA&%Y{bF>^}bA!7i zzhu*7lIr>~7-x0+LB4OLAX3- zHjTMEV&v{zVCS*p>*G3ggx1l=E|9vF?cLU7Sf!A)y2e2z!?SS1ji@^D*jDwVzY~(? z+`smP^x_tgFCUg=>9vaBbDoEz9N&I?ArcLhPn*PLOL zvdPN5ym#mP{GRZL2(q=n-uPwV*eT^_F`u~72rGwL@Bb+i{@m4|}Lqz<3s zUoEb?;%j@ARJV7xKr)FZ?;dPp7#v{x{{Z#tveW!Ssa)uZb0J|gj2GlZX*YWgcsZWJu+B_Q^7o7*pFg!QhP6LRx5V6!%uTtgS5anWT+?P}2{W zYMhK<&4(_W78+oqix8*uxXav7M%j9?MdsO#J7n)BUK-pNtsirW7D12!Sj?p89a5BphOI&)ry zs9Nc;1)SY^OqL5QK<9LgoOxpa;jzixfq~Z~3d4$hK3N{tMG)J_9z=@KOrBdY;a4Xt zqdiIg0PF1N#tEOc@ZKHMw4!m=H`ccH_iG%o#UwH-gluk+hDHxT{{ZT*Nz&x8l4x_N z%WQ5gV`dY#+6y)TVTR+A+py!_ux`8=Z7RI~04m00J9B{HM?08y$sIYadS4Fegr&?8 zTZE4BcTW|=dCovPenLp;{6Ka9^{+1w>8_{iSQz2!Ti(?5tIcmuR*LUVx7AlsourK3 z$*MC$CP4&wSQsD^pRG3CwK*YVZ5vS3P{J`h5=LTDrz0xF9D+KJZ%Xs+9xZ8Z{>v;k z2I32+Z<;1%kz0}U$?xf2jcwxp01@e;-W@vHGc0m3ki0@fR(_)gk_VyV^{zPLmC^K2 zr|hDXEZ>>cX>e+@MPnlACJCQVD*sd`q zNa>J94?d!`meudt6^yhmY{EvCFfsoC0>~haM+ertZ%pxJzM}+jy`-@_KIP6pY>(5W zdajFcBg1PnlWa??W4$s<43oj{+r4qlF_*o$_-1R7*1=9voNcLn?q`vM3#g2!%#LA% zuHrkf=ud2~AB|hHY23?kaVirtui90Q%)X83gGe?z!RABeTgi077-DU%-rf1C?21HA z=617rcHP@WDUL#(irnDiqhS3jj%mh6gURn~TsHP?nZRJs%Dz|b%PUEYjtKd=;+bUr zVqFGX%*?6h5bRK>Cm%0BMo&KY?N(!VTURn$#zaSQK`dotjd75~^dW&5`V-t!U@}Vy ze6q}bP*y#mm$2)D$9n3g6%%;!++@Nff#bJeLd(eqIZ^mynqx<3lB~%b8Il(BB#txY zDv{6=lh*^&ikV zS46foe70l;*v%VBJFHg;xA(Fk+qWDN2e&@IolZQvTlBlOc+ATXQt}~a*baITkJFwh z+l{gNI$TL2MI$rMa^Nd4`?+5D&tt_>Gfg$AkIdaHw^?OYJDB4G`u=r|kP26;f+*&W zHq(OJM6s>2wd2hpB!oe+5vNgRODMf{Dj^RzT-)56>WsQ}&jQSN~ep8Ned(|6g zguZ-n$i=6*GJgJI+m9@AThWOCeKFWo$u0s!3tFUC5@mxbsWKj$vNN3Z=Bu7f585t5 zM3t1ZW-vUMw|vL%N%(R3`g>J#J3%VRGO8IEB#aXbKMZ4>_VlX%0B4;VS5=l*c1Yxe zL|R2Bp}_pfAB|afmSAlsxRJVw0F(6@FkN^iho%2)7&RO!xS~4r9N0tegvZ&qW z%F+$W3F8B)7#Sz&NpfRIl1Lim z>_GiRTD?&Lw|D|(CEAD=cH-GNJ&tqIqI-N_T-}M5LnKQj#FD~%$=H#W&M;e%$sM@u zO5taZW62a!w400<8&nwalk*Y>PK)0-t$l=!iy%oR^G;Xnh_Rf6U8SG1AIx;7UL@)E zLlhg~cP8RvBSz7-GC0S~r=I*^an`BGv8zPZGsAal0~9E&lxE1u^~w-N2N}4t;^8eSZpWGW@m;|atg9#w?@bNyz)TztkzizM7yPF zl4InE=U{gn{{VFL9*59+RjH+r5X@Ot1>L(NY4xlAQ4bx!5QUftA&Dkc+^R9O9?ik~ z-ns9}xqPn0TY)vYB=?dgR@`}!%aJA14mPPA1|#Olz~J}mU79FdB9dch!sQi+3`Q}L z%8*Z9oO)G{_5T37kmNk7@fVb~)(1aAKf;MjQarv^e6j`x2*{{z`|e|PZHU??ftJ$d zXds(u4J31k;8_P?>Ttu{b*Qd>#~sDHy~2<#HjSD2LF03AgVgl&r=ucyK1^S9ZV;&i zZXZ#Oed*RwCA2dl2NKUK66BU(q>^w>NF3vi+;pmqtZ5rqkjDZuK?@d+GJNvL6fB(M zZzpn*&hK(DO4B;rMD1{)(p|31yO#qPCxf5!>qegov{T$k7Us9zg=5POK;!W1^vy*z ztQQhS-fAtmBkd6|JCuW-57vt-l&sk&+T%D@d3N7TD3FUo<;2PkIUH?0dFP*MiaF8? zC=IM&Ph?xk{n#i}ACzG6$4nk6bpr89{{Ur}&SaHd@+k7sGdF+7)cP8GtgUTwusIP% z#g!P488QIK8NnI-Y3?;<$!^^uc%(x&lRSC41xD@IIRNp&I6eCJ>sdBeGsd@BF3?FR z^4O^amHj)`uiD{wn%*g6c!uvTNOJLs0KrW91IMpgWYNnQjaDQAXw{pNRZpP*06*hS zQ+8xpDUpcZ_sctp0*^8qh%HLS6py+|{vp68p*bUiRUj8q!#H;lG|Jnijvc{QJaB%W z&!t}mQw*V{&e)Y)NaTYaasrRxIXTFu#T4wuDb>;B}KH(t4#XjQzWds%n8%8pB05gN@?^U2!e$tM{ zHQx(H@~CFX&ws~^e_DN#sK^0A{VD~ z=kEc{O_?<5N-trI(;~_qd73F7e3C;6k$l2%2_1OoN%!qqOE`)nXpyYQL}q23Rb-I% zI3B*Ds;tlDn{Z5GKzAHxtui>RBz#JjQao|DlOz+E)G+C|V=O(m>sm#nx;1cYoLcFy z?-6OsY9yQY<4k2mSHbz)IW6~g@y}06t8N-gQ!FoZvCDc4CVO&>`02PFLjZp19nVUW z%u?^LN+pgpd0579272cMzk1QSy^%sotg^G0y~gkVmab9#~zO&O^H?SexbpKab`r#D*md zfCUbNc_3~Cj>L0NZqh_{?jee1iFU&XEJ;D~u;ZVg{#7Nku(iy$IP%e=e7FUd%)!T} zb4-pAFQ&&uwCfYN^W=SJ9k`(z{Y|}HsQwFvsWlX06E4+#Nn~HPlwzvq^Cnj!!I%jH?W;eLd<+sV-rc z?GXTCh%UmxTX#RG#yBI_)|zr=lIGhDD0kcm;uMl~rFta!xy+dZv>U zBF;9qo>`dhm1F)Mcm$pfa0&YQ)RM4K0qar9v0H#(x6GwR zRuVkS4t9+2GJDqas!HddQcbp9xJE4;tkHucd#${wm*yko!2s}hCk>BY`KXLA%Pi=@ z(kv>=F^rJS?0-y(s2Oo9LZ3RQX*Zm*vEw{rjPX-NGfVb(!)Dih3wgx4woY(5V3JR$ z!1Xn~-OLk`*pe9KvQ+X6sW+a)+#tXxdMF=Ef_sC~n%m)qOLUn{(3{K`BPCZL9CL%m zLyq9%wMj7ZGM;S1WURrrk1j>z4myTYp7=TTsCS~Q*5`r)6_+Q!K8GTMs+^>jrRbl} z5kvNAR#`)N^MDGBkCc(Y#(VSBeQKu3?A*7MB$5k-S$w1B0K^`iquf(%?qv|B`C2w8 zRz-{e$FF>6@fC7O%(n0>6I+Sg2=O2+-fnO(qwfrIPaQuR!Bt93saHs$=e6l~l^w*t zCKf`+9Q7T!{RM4^cNlG@R7CRCS);;*Va9mKImaj0p5~~uQ^e0Zv}&mvEMv(#Rk5@k ztAa=;Jo4v}8_v-A2h0wYwy8DT!UgPE-P9 z^xce+fz$j=Q%S9D-j%ale`9D|0(9sPUNp*q6^P^poi0B?B!-djALI2r3z zOqSu++$Jq!xNVVuJl4)KS+ICL0`dnwrn!!Lwq4W7m0hNLlxPbyF{Q&sjM(5X1O^%G z*#Ps@Rbvt|n~SuzS;DHw7I7m+#N>tONF;RtcJ-@LqemsXM<|7ZhIEn9rKhxg^M7k~tTA){-K}a;2hYR%YPf@J|P?<({-5Tcjf5(7>|(^4yX# zNH`yl)||6u?m-qHF-A75nA%6{QlyhYpcIOCfG*{1s;ZJs?)kv<^!n5(LA}2dwt{_z zM;7Fj1&`E{az|W&=~dBTA7~OAueJGEY4?cyv%8hYIRt$UPq#ZlQEb|2 za_U43%N+LCh_5aKDQLFrjGU>#&N#+ywt2C$NUhF$;|D!Gt5XVaZSF~GuL8V)?SaaH z$oWUF;aaf6aN(v$j!3QAKQ=d)3{--7>UqKEAI_mG6Ev{Ora^2*;~&Zwj{e_IYMjF2 z-^zmFqAik20L6wo_r^HIWa_1}ItQFi8W~_%r3N_z+s?}xs}u5roSY8lu0JZ$!x6i8 z0!MUp*u{xYz<)Y*yW9^xDI08i0-%f!m=2z}ro|VP3*DUjs=`m4?i;c*fzAdxj+|B# zsVCP#OO?A0SqPb)Wps)#cQ_*egY?HWV(vRxCusyy0U`z>X*|MPgPwp4o_c?cSDWny zW`-MSZiLqB`?Qa8u?Nui&N@=ZcXdCP9Py-66d?oRH8F$8>C_DI-2H1c%wq}-$ggQ5 zn4O+wMTjoa4&qqxjywH*>c9@h;7BA6syw^_wU;N~6xr=gUJRS1kz1xFdX}oU;WiMn0e6?N2i9xMdNNM2fIS z5hS<2=4-Yvu`;BaBeIf6;+034xmzWbHnR1=!SwD;S$nDO9(WWf+XtAE$%PEK=bkwp zpW{*Pl*uL4vqN*ZA3MyH_dMsXJ$|N?8051n6_(Pj7s(0~3?9SV6%tJ{91`eWM@cQw z%P*OQ5tYt!(A8+xIM#cg^!C4*irmXR*l6Tm;n;wDqCdSCm9mm-#E{&a!v4AWe#y{z%bhiH+?w7DIUkR$Iti9|l6#0YMK#G0+VqiB=KyCU4l|RSXPTH*=4Lf7CRb=p$&TVu z8u3-q35G~j2P6a76WXsvSilPf`$8`<;FXcHz#sj3ibQL0l0zk`7Wq=z?%+n!Hc!ff zoyTY=9^agjO28ro*xxe~f&jmr<-2JFz5e-cInpHsgWwDcrao z_{~KGvMX(oQaHB!s2sLOuDB<@yeo!UhZ7@y4s-4#ls5P9d<9lyf0q`8f4@8p3%kwj?r<=d#LvD$goRaJ=eK+e`qbdh1lt)Scw!~Ev8 zYUgAq=uZT;-#DFap_WU6w(&bFE3P^DyAW^y83#Rh8Hz?zF_O|3E3F%o* zoLVZaxqQiEo@9J_API~<+y2{>UYUD&P zMq534hACr_P_z_&8oDx24x1Z}z*)GEfn zlk%}YGLeJZl0eNp-6fh>kq_?!Z&?8`vjNohG_cRMHJn0a+TmlwS->Z_$4{+I5ly0H z-JBezKqT`{Ex45kG}eV{hg%j%5nM$%88LuV9+hR8p>~;7q{J*;1{a{?pYf+$MI83w z-ZCy@&yazLQhoh?pF`S}(IEj@M5L2&XrzAcM#~ z#%Y$fDRmQhkp^_hL;&;bGyQ2_4dtLa%1GOtTsGixFbFvJ&(jq&5fKo#7U;qVgB4Nt zPi%cX>!vZW(;K_!M*>Z4pDt&P-QknZ2<3jD_9Gp0{c2XRHt~ZTq2Li6qIi}i1b+&g z;eZ(T>&Hq)c8JJR66jXK7?C6@lu!;C>#}5^Coq zRV2s4&uH=L2+t||S04LkIIQgo}S)^;{GMOW}n3z$9raP%$Bc=>rP1<4hk}^kj2=4F#ir4nH91RSIFizAjpgKw z6_bpRdF}P@Ql!?*jpbfj+{p#P$8!u>GDO+OJ+bOXOmm7^Wtd&1uFG)@kT&TWU9w~z zgO1=Hat|K$n5%f#Q%v!s1yrbpDE5uGr~`c_F#w0T}!Qkkujbk@+e z*&04@c_SIY1L;~fmoIS|sDCOsq*n4#inigaSuNf3(voYdX5P*_eelDXA~{u*d8#qSKEKYTh8cp#CD>Pz6C%RS z2I%2$n~!719q~+t-H)2`K=#QZl7ellSf5NDhpr7a+DpIRwdJ&t4U7B91_LN3r{|pe zicD_J7j9(OSt3O)PCiUyj-P?`6%>pETyIo}ADT#GVnl1~c{m*Md8t{?%Pf+Tl5O%K z!m5LeU$N zkeQXk1^G%5y}PdMD4iuhF zdLBApe=4%$&9%5=61j9xupr0G4_prY>Ph958q`8z^CTzAkjJ@MK;W|U4ci&#t!CkH zRx87B!f6sat21*GD^CyvvqDD!LFHIC@pGM|4!IV$waJ;8qm9aLc93A4^ym&VimyGj z%UgY(+V0xkXah9T-C8kkF#iAwmE??I;E)GB`p#p8qezp@!>X9dkYsioaslppA5rzI zjBH_K-sNQoo@d%4^CpazM2bPw0&p@wB>UEk*9_<+Pch;FRKouNdv-ctoOd;lrZh2c zVYW$I%zrR^xX8z`;P81py4JL^?TthzeASRJa~L^dKm?BBovd|Jgvye~87|iCBHA%; zC`dy{WdkKgLCNjg-jTOTKX}d+5U4|(W3T!AYeHE3nT@oCK~`<;3kfpAsRSLT+XuC0 zEY6dG2Ki!0#udO;Ad|@*kF6^!8gp5fC7L+Jx_NI2Yc*tNWg(QY&O3}8@IdSDRqi7a zNN0p2s(`4Z;e!t3eMWt%jo1@j$9AhE;@T!zRbwMEec%+30}g{A;2e(CcLh>Do?${? zlh@Pmq~e$-bXPL7!+Qpz_T;sj1P0iUrLCJWN7A|L`e~ZZ0xPLDdXr8@Mc%tkD9+S0k@IF@w^Q($KZb`Gd-WRaUsZkb???$2bLs+;TwZc*&|Wyi+To zmRq^xjzG#0PtDK|ML(}T^?XGd%@osyx`|ywTPw1X2R(7$IO3|Swaw93Co)8ZTIXt# z7Cu16H~^k-Ixo;?jqGezc1mlH)A%<-_190!q(2?ss;gH<&Rm&Lr(B=U%(+JprGl>Y#C zq4dvMtvE-SQR7>1@JAZ1+{OUsfzA(ZK9pYPCWXbihIE+;juMhEjesC3=Yz&i1GuRH znY9MWhDqa9ard_{0B7n*tag`l<)K6JApP2pnT~lTwGv6UBgqtq-diAkHnVpC_aI~Q z6%v(*O}1Z#8(Vdr;y6sFdl;YXB1q$4c_d?u9F3!)$33c~eo>L(^Hynm-P55zyhLJf z$F2eAAMToRG=&m0k92->eW(dSI8ZnXkVnmv$tND1)p>49BHJ{m{!48PkSfSesVWBH z`U9MGs*IC0jBd{$mh@Y<{Cl{RVO5Z1k?G&_s}jj7#|*9IkvxZS&InvqDQlZ>Rqk#K z>luzajl_A2j2+m(IR^)dcn;rZWmx2f2^Y^EaZ`oPRB%Rm@@U+-Nux?bZ{>+miqCG~ zksu7GspUw+4`Y#2!2WH$vtfSF(5y-1g;5IfLD~Qd$s^?zMCSF~t-#nrHOqaUY6!_V zL?n}y0dmK#NELo4;hJVd^OhnM$g1U0wt^Iaz{n)?*Yc+H2+6WZUO&$=^i z&6yf+@8^N@ec(Sji|q0bGFiT9WnqxqvZ&|$nrvbRCV6JNws_?N2$B&bas!gZorq;% zKmY)9lbm2ww=Lz$ueq6}jaDp@2xG|{jQ$nRQ8sDOmm`Vi{y#`+YYk}HBGwVB#GX{1zTV)!JT!zB9gkMOB2 zCO&yYSyWrix@Txlma*prnYs*~IqO^TO9;71qlVTdiIw6lZW=YmVyA`#@Z3j6 zQ9KYzF5$YIv%?YYHz$yJkRP(L51et$Zlr_TwK%7*gNS*H!={huLMoE1BOIa82GGnS!I+n5XZL}9XoXP%_*daooO=V#iLs8wY~B` zbgL>`-@@^Q$lMzv85kSBS$3Qde?GN@qs)wyB+GUx zS~)Hqk|_-5eYqQDAf6lOc&R+gLlkCIV96)?OfkeGW^M*IfO1I22^@M>UA?)tjov9G z{pn{yaKbe`v%$giKD0?JswTK-UDhd8WQ-HJvN5{@oQ&jufu{&rm&rJ$C}lB4AC>0J z_a}77*xH&<9`-TFBoLtP$HY zJhR9aX{3+$$`A04oRg2ru3Hthxeq!sIDw;O1O}Lm#CvD__BrX&C~@YK9TLNd68`{4 zva^${O&#gEkPbn~;Xovg0PHF7+nHyEGXkZu4Z&m~RH*6D^z^1nnXxs|w#X$*#G6^Y zH)EC{05W|l+1qG>*X>c=h4R6BQb0u`fOjZ7axysd$mY3gRA}gxFLuLWwrh_)Ev&8W z(h}w;w`OT12OKbBKZ7JWsM%DBZPc?Hm~-WC zDozhvj9}-ddbur`o+CB4mlGeEk>+7a%(j)j&R~<| zX5~jhLktt`+;pUpMpY;w7b`n?awAUAvVuNlRvhJejCTXJYQ3!Ma#?w2x8NN0Z1azy zsnyiP*?*ZNY{vX;$9#Gk>C(r27}_sTf)$QPQr)IVpkT+(aU&29IXLGv0l8oH+V@aay|>Qh6R0jjmNf2DmbYZ(Lw) z=RYrDj%zL(Nn=Zi(EXt!CuN*D5=eS&Q=A6Qc|V;y#>ZVZ2DL8vJLFi6)7#?UZ<;8< zB|SOM;z!}uth_5Pl{Kl`bg0TQq^o50KbK0a6EhTLLKIRP6juA^T7UjsNyjMxLv3wLaG^9klp_PI&4-j$t|>#x9<_mk&_S- zAZ%m~_&5ieB`8~SlBFnaX?>bp%LE4B%n>nZE@u$Jpm%3uw0dNp=T+c^7=j>qw+t!#XVVxBP4MI*PB=8{H7E;Go;+&KDFK^cj7(r+oH zJEXdt$i<1tAe?cYgSP{<3E7!RIkQ#ej%douZ*gxevE6Q_RSbFHoMaVY$OqIO2&!`@ zpF77BBr}i;$X9abZ&T~oei*3ddvl2X(w8#4D~OGo-ZRaCxWtInKP}~#A z$3v0FzA6cAqH!ULc;|%%;!KRn?Vd5muiA1de5{Qm$d%atBGL^3oRmQBwp$}*=t zhkms)&2=NQM=l@`0*q9VyBufO)kZEs$r}$V^Uks{id~{Tn^eZ=PDw0th8$oHpqjd^ za27}=hHEme-)9nxGe_BnY%t_|8m!ZatQu1u<|>|U++}23@_ni}$NEjPC}Q%!&pN!P z1J{y&AzjdexxXYy(lH#+yUQ9y8V@!Cj9Nv{ML5Eo^OM*gTD&Bgo+)CAHn-Y-(5%Eh z-$me$ereFXv5ZJqh}54b$V(Rd{09ixTad31{{VG?7$brYJod#o z!%{EG%jmzmU5n(yB7Dru8)+nioPH-5s&YlP29x& zVDEs_NjW>DY~YiDjo9b6N>LHLcozYr%QPUIC<7z&_B@*5o{}+@D9PwKCJQPA2&*DS zp);SK89d-;AJEnBEf(ew*i#FuN$2kJRY?2J2PJ)nHJoR;htFGUc;t!po3XTRAP_fh zAniQ{N7J0t(9Ljdf=FXYh-NM2lB>=Jd-@N~txdKnRNNlqPcln8!xV5vV2t@T%avGR zIlutt3!Z@fbpl55q;bATg*bL#Lk~_r{Z(mEo&=Oh3=b|On66n=cggBhbJna+8iV$E zn*_p!-8Tj}Am^t{oswsul$(kuB&%~91ZYf4C+^o~Sjmy?+pj$^eQEFsw@n*O z70Ydrq?SU;`-#W^5zkYTp4?`LSo!53nO1y!tbmCKZVx?q_oi>2Wb;h-5=({hl(=Tw zoa3IEJ-zB@PUk$=yiU=!A!!vOE{&DQIb|6Y5I~=1ZXV;!{p_l6SmUY2Gg34`{?9oQ zhE3jL7Xe#6Pjiq4G4J%L&z7-F@yWCur=AEM>XN$(Yu+4>F@H9A;sR@z@5#*wHaT9A|Q~g4t-J3U(gc4E}%Cn$oON%QQ2qOjM}G8KaGde`Cm|nE+P#R7T-) z{N+gO2TUG+FRgBBwUIczk|`clWe~tZI9W=`Cg5@hT=ATqp1o>>mlND8$+9M7+vNc< zEwuMxjyvNX)Xk9GO$zR2O!a8&toeZotMkKD;Y{?=v3fl zPjwo_J+j?2cMR~z_KR@Quu^awfH@f620P}ph162p%e&0ARh+Q9VJOJ-N z5Wn;9)}vYHl_9oQCdfEw;gc!@bB+(E`1;kk?QJ4y5^2xdNK*EN3g$DNt&ZPb`1YmG zCKHN%1Y)sDOQ0@_3`7D0Deiv*{&P_!%u-I*Gg>6^x}DbSN~-aUf(SVsMt>aCE|(F; zo?AyN7TRstvbbFR?BI+Lcplv2G_eVu;Iat!c|}lgsz;~PJ^^aTthqehg~)0dv!inC72wBah2yBQcIl=LD!8gTEg1 z*0@d^VNn`wK3bB@q+s;*%^a3tWGvzl019SViUznFcLZQa;{=8TVD>zb+a`~i`{ZkX zGDHkEd5Tq!UP$K$9lo`p7?q4@6{AVE{_k!G1EDMII~phZYB7o|$Fkx~&2w$!ypf&( zZMi&v4}PYUd6A7&ld%@~hT$@1X&HXaK5^yX<+FftF`ftX#Z7H?E=)HDDW+McVr{}S za!3yWR4@fwzs*T%ZWdK{NPbo>enBVAj(H#wIR3rOOm1VjQ53O_it-X*aT^uSKzS;C z>tzXCm`QSqu}2lzwvI-TN%{9E!hKKl{{ZXLS;W^!vZ<2LsaFv=Rw@qwb;0Y&>Bm}f z2;qh2a>*s^rLJBJGR5|Qs#|XxfWXP?iiM-w2sY+H8%k9!e(M$Q^vLQfQ(08HCus^Z zTX{Q5$+&NFS+kRpPhU^+X(e+tt2447xA|9q82S&O;;bNwSP{-%SYK&k!*5={rAQ#Q zb8)=JgUMAXw3!}4+-)58=RG>}&2iOnNY*k+BoNCTiFqc**zHu3(Gsf1_`ZWZX(bOJ zxqE+_ILK+*7CerCpJT|)N|8OeiL#z-VT__k#F6pSAmkkT`+hOFYnbJN7?#{4$F#+@ zV`0x29P#PXky%ry`if0~wDXl*`DqgV@<%94j4{9*jCMKar@axX-dnR;o7p5tcU<|F zWh0NA3?BWuR1oFN&a8ftH@eAiKk(2EF0G;4F3SUBh;=t;Eas) z8T6%4hcg%RX7ZIsm`>dHt1v?h*(6IFqe&YQ!M7;ujyTE5$2ElQxzxSVi%TK7R}A-y z3^_=oV9eg6@CJDH6*^AV@m%>1#pPh7NeaujV1eo})cgC?hTF-W+sHeNaf2&6autqK zjCaYUipD8E(Q6#5J>*iIgN?(SZCqp!dgtj~FqM%`N=18rDm!-=%#%8)cE&#nr@${H zOvvE;tm;a$XV*Txt3e};Wn`KBs65fWI2}gNrzv8E zWl!Es6kDWK#|wf$!ww1TDr<-yJ98Q=t!k<_WM^vU^cggc6lzjK9kU?VzFIpj3CC;> zI&`YnHwe*rVq1vi%KU{gr>=R=(*x3%A~jWAg@Q=s#4|~ z0I$fbq`72f?#8{!nG zSx(!q=PWkH86A!REP8@FWBe)*#<*`di8w3h2W%Yk{u!c6J9lq0%2tG`uv8ysDIjL&S}0$8$2Y zY)Da_{`C`mhS8xD+<6G)yqA+ak_p%`&*%O%lB}7~lO>YjZPD9*pNDO>`2mXKr=Y1~ zlNOfuzh{&QCgEi~00#ruk578d-Erom`35*#E((^Asm>13$>X@E>J0BSw2-MXESPk8 z8Z`^t;~bnGo}#*;CYYrjQBK*UWt<(;NPM7k@`5q|{Y_nm%C@+}x0uobyJlilbNpO# zao4ZsP&B0FLbgs;@v+iEh}82-@9CBP31YSG6c64EPn z9dXAzK#1ca})&pQd^bZYj+a z@<$^hoyIZp+zo^&8RLLQ9FMQPDAa}3jH)E$Qx1?i7m7WP2oTJYZf>M*$DL`Vb6^j;ge zdBz4ups5TI`Eb3Yt8*$yyfYP96cQM*T;aO$`i``hi5=V*XbP;P?q!fHg>mXe265M#w-lf}Y_Ld@yu~oY072mN&Up0x zwM|s)i53-^q6?hmKp}pg5TZ_A+ z16$2D)@4y2MU0Y1xaU1RYq!ySGj($j5~3G!c6`4uCp>-?)A(CL`z_3p%DbI|ETd>7 zcjNqP)F89+t)WYN$&J8F(T(c7{LC}orU!cHb%$i*iV zBvFy_3nRf^}1H>WkU zIi$?d3L#*vp8Y`UgV*t^G{wf#<(0-;2dK_@r`JptfG1B=&m_}W1Gt_>IuB|jaEeJ8 zB;lJ|SZB(LS~BpC=e8LP2G{{VhDkIbJU$e@6IPk+Lz z+{GfwURgs!9Hpcu3I;GoeuLJuK#-sa3@IUOoq?IMI^<^=;PcwCa!r#fgG@w*E!%!f zC?s-6T3o;&d8ZK|T#qrEX&m(@JbL~Wopl&k{{VXKbB;8wI-|U;2dKo)b`KTvTaF<4VNuOBU~N9kR8fF6#0<~v1N0W+I+U!dH1N4n8?78u1@BV zkHG#tYC_Tx&H&%?^VjQIQ@1Ii+=~GuP0#za4YgEb)31I998>(&-?WxKVfl8izg+%Q z!PK*#pKuDhOC0t%{C~!!nKD(w5wLQBa$1{iA$CZ+`3ynyz^7w_wDMc2B-I`A2>>2j zE3%QF;U0k1z03g0U~{|X{b{O+p%Q+5YK7{kh_lNiTX4=|QOE>jaylNKwQv%kDajyl z&nFc^^gA3Rs)!J8Tx6bk6x^cXQjN)Ac3`K()?<^C>x|=$I6qqI zE#UlZ!YjD9}lnw@Qi3h$I9?gyT5sI({{$JXY7&UTuiY zy}Sii90u*_TJ5DnX)8|&l*PO1r_!qVMo*F@KrWU3(e_DjsN9SO7(9CLaw=AbJH$%o zEh5Jy`bJ@BmNW)+WCUZL2kHJzRY;6xZIFoJEZ$sE=VU9`4D+-eImxX{xu$|?ZWd21 zo-(%tjmlIW-`yaNO=sIox2VG2Gjzv-jhMp@{D67-3UZF6#-yZ2Gl6XMo9ckVy(jgD@l}DB3~$jmffCn$0Dpd{g5kdjRnMq%tgs%U^?fa2dA$U&(9bx zhDmV}FlnvT%CwQ5%Ge=E7{MUaT)4Y3)c5{xny@CxJe{UqgLZnKY-jxEHQ<^ss}1VA z{hgP~HkY1QSu>x!2h2M0^z^LxT-t_tCdwp>y;aCi=OA(XN&!6d2BKLEP)hE0rOeFG z{^%Sq1Auz;1B$gIjT=%rxuzGgJT~zeU&Lk*`7BH-z zGRYw1sNjr%bAy48*Na>0+f{k4o=934NixB>F;>Xn4p?nJj%sZ`P=@78qs%P#ZGcLi zTQcKJ;R}ZgPM|v&{4Uq!3&A5=< z@-yvSGupbLM;==!1p_HkM{mOztlPMep^`Ef1_wKHgX{dw4cvzp*x;=!Zf8_jWQ@%T z;D!Tm`kLtNqj;U=HqcJx12SDo!F<8S{I6CR$m_@e@tS>}lF_`26US~LQoy`LjD(&r zeS7oiSH_br*GFJi%?xnd?mYB8M+fw(j;xgnbUEpY&or~$VXhy=&5SO(a7YxMpQn3mBtth^^I6?wn|Ipfx%7F(j0(kUNq;_^uDTMBt2EtAJg zbRD>)>P0ho)V{}=%i)RQxVm!0M>IQa!i<%0Ne2fYf)BUj(z#Kj1e0as+^jJTz}rA% z48ZZboD36;`}eP9ytc$v*5&^Id%0OuHzh@J`kP;v-Wy{70A*1po{^`Rp^3th2P9{> zJY>^SjEsG=F!V^$DPWEsBWTX!xA=MMURUv-#&Gyw!aL`=5!GO36 zxGs1nECw;a;10FxWz>DOW!UgDyhkP$T(YxzT>fHzX}x0S#y=gk>-!~=SJdy)2`w#@ z#*ZSMxlxR6BN=W$Y-{EwnqLnjOms`^tIfK_yN($UUq1 ziSS;fsrbv{zLRkpYRzkF;y9KVqj1rvSu-F!6SSQ0KfPbtXY7AzZzqSmJ9M@a+21v^ zF)K?WENd7Wln96$Tarl_Cyb6Ve4O!9t(vICt0U@oa|v4mkVVZmHnn$O*W7-AYuas` zdR!Y(_Qh=$faAa+CtX;kL{So8CG_T&%P zZxE!nvBz)a&NsL3c4QF2PfQ%(@t>&l=kufXxY5#mAY9%?@k4EIw&dE4r9z)vah#5Q z#e0+z`oAYbw}UaC+1yJ?rLT5=Yg+53#ub{{(o0LJr`tW1+?$y@k&)Xxj=XVSQurUl zx6Ns7s$SVmac`E6Ic?)A8bG0$cODpkQy_YeTKH1kKFO-j9ka>y2&I{a+GS}OROhKZ z!Rhq;E9|d@6KU~yavMETNv*ErRhUbwMpj7`hEc#!cwvUf@sjkZrMG}eOck1P4x+7k`E@r%3HYPh6wJR znN)uW$;Q*~lgD03uTuvY)JOAgh}arW9nWna;rgGKzwlYV2mv|q>4q3M~zjOA)~Soi66qFy zI;<3MS+ty9lIV0l1w1PLHu27n;r0k&y40ds+9nGl#>eIW<3DsBhw06KYySYVFTu-? z3HVpS@K|c@G^<@M-TaYujKN68Uy^b@VV*xwYxscpXX0%`!TR-{r)uU;vD_;eA#JPx zJ&$g<&3|hjun)(N3HayX#+f{~=6P(aVvb3toCY&+cn6XQ&wl;*ug`Nz3R#Rfw)`%B zm6zhMw6cju?fM_4(RgxHjJw>%*5ex#$OMECPuXPq6+9DXuW7E+%RR&s zK_q4?Ns6~j9!Db{y|^{#cm6EUqY+%me{BoTXD5|&8U~YT=U^uXX&`4G%nbNPjQ%ia zIv}}Ou2#~}N3>o{+m%UNAHeg*KgPb70nVhkPld~;~Dzb;7+4*hW=OzItNDir8|{bPdxMl*YB776tm+Fg?BvKev7I@ zEzY9I)4>$DXI^k|=y>GgzpZ`%>Y)`ccPjq?g-36x5s0RV z1PLf){n!#@@z>MZq=}wME^X#zhID_KvBAwE#~k-xWoW*2Z}p_`sr0O)Cd$2tAtFny z%uT}!b}OC&jPNSk>N3k7LP}-W6vjx~^`OL&NXs0UjDM^p4&pQ09V&UHw^ExMX(wv& zwWnw*{60<0d6;;5`+Rk>B^#1@O(vPw!VRLOMiDYwulBAkpRxXGEc*YncgtDpk z`WkSZgGw1=Qwd_sa>~*ka6Xl+XUz6Aj-%mLkg~>Oi6LfLQbW$~T7|sZaplAZl+%3j zH_eu-c}4;-(V1soo@61FnDzX6)n*0{v}3C}Gt==xZ3%e8v|w zu5Drc+hhcpn3JEFwPiJ=ssKfk1(~IjdD;{XG4EPu$`;TDF}e9dWEMNVm1NHyvqu3@ zx!XQsg211DUrOutlCe;lms2j?)lAV!$IF66WtpFG$?i>Bmw%Ydyu5*gE`I4;f1l2y zykwd(5fN5M$;%FU^`~1wFP7HhE#=$!k8owms^|3U{Hqr?b7-_yvx-B$M`eadLad-S z1Li#s(-m$(=11j09EmErnc7Tl>(p^p8pcRuUFK9mLo9C}3^CaM0AG4gjSRBf2{##f z{F%o;(ykR9_9047p+FUOp50njSfplhRBmd57!(AN6{HMGpk>_5ewCuJT}N>|cJPUz zmv5OXWPNd09vGo=k-*XHP8msH+;**frAwMwx3QNM#>g5uM3@q{m=tbS{QHVh%PNON zm2J`y<%9Q`zrvU;-bkVXPn&Z)pkfI0%@P)nq)5kv+ND0|ZsMiBW+sQ*h~)DcCRSHP zL6lR7gCu1s*oUJY-=10H5=U z!ll?8?8wqivE_;&84SCaka@@RtMkDadvy;ZpjO?L0JOgKJj${ROh;b_f0#nh9;0NaQl4$R*Cj;D`m`}_7O@DKL?0F2vE zyPeY7%0)J;vYedysQ2~az6rCkxSCHU6Z^+Fz~=;>IP^99!TSb$9k$YZKWDFMOC%HO z8Fe=CER7+?6dpmrVS}DP=N`QHj7L0FZ>v3g1#C4MoYfzp`kSK1aRsz@e`%8GV6gJ7 zjntVd7(A#wxjV7`HHE8Qt?MO@+Iq!^d=xc3Zo*3d69?!KemF1ET&4tc)0=W5yxb0jOYbiE=Kw$9m zjutmPD?o~Sn9Z8Q69;(OMs*D#UHQo1oSYs<)1fu`N$`VA(k-+bAF{@_&Hb7hWxIfh z8bj1!hE>m89AIQu=TE~MIS#X>LT%@g6mZWWV$sH==kF3&fIIVFqTUmlIV@i4L>7?4 zm6|CSBPk!m27c*Woc7N=n)2mJ6>FpN{xqiPxkUEEWG6!%vpvf}2IPV~6^U{(PoT;F z0LQ)SY*@`CLfq{Q-F@ml}p*P@ru;yDI5dAs4Vf@yh%8U89a61R?X$~7Ul*ze3QwR5(L7r9?W`Cb|%yoHIgWx9$)U% zU~$Ro*EkiTW)A$?$3vvB)M1{~6^tt2WzIh6&oz;McZshfwu)Pq`z(8-h;4ZW@4AHX zxb{C#eJe5ENG;MxoJJs35?jfYXC#cCoN<$n!``$VB5P$6OFY6A{nUH6U=m1C=m9>x z>Z7^8vyIG~Y3G{SXmKQSuy2~`4=}0d3o4vrC!8F0r1At&$#V()VTXzxtWv=T6a^Y?8WsHN3& z*U*p-JAW$ay^D&1G=Y{Ev%K=ANSM0CHz9WnZc=)886M)Rol-liv_^%V2%}|KWf@Z; z(aE1P0Hq(xCG^h^G*FkY3Gl%=1eq zFt->OQP0cHdG0aL=Ymx)EypJobS-OdiLRdEp7RQ=EWmE{KSQ7M#dDYI9oo$u(y%cD zvR8}dc{?2U9Xfi|R-Qu%Tepnm!#E)14xsb+RoO2lS#8q!ru#BRe#|bE<~YbKfd}_k zlG*;k(;P$Gr>TTpjWf_(k zW@cxDdB%A;2d`d+y69ns;jSHbBz|0mS6eliq&eVq1wmlBVcR?rSlYF^$*3jdmTrp@ ztF@)0f%4>ohB?6W$Tf2cRMkd~J6+J1QjSZQ)Jb(}H#mUhq#zuwPeMq>ezoSOOw^{5 zIAGJtFpRU>Lmv!(PJ3p(-8BeeS?864ZC~_>V*o0tJ90?v&N6-LmGJ~ORza_!mUAbX zyKIbVV=?zo{2ce^k9y##1t!_plZnOMN2#P=Ws)X}!rnm}+Q^Et6*((~$z{eeNXQw% z>M~tedA8>JZPne{+sMM*rpppX9dX~etL>{<#rCOgt>HSMkGRiFYdq=1_TY$sU>Ha6heEOUT2(je88F#~Qrx zTtaQExPB&)!l_G6z6< zh?^Q(^~n9Z+qo}$&rG*@KlbYrA-a=lajGrB3u04bYz^&z?A@dj!!+a z-l@ZFYk3>Nd@iqS8det;kXOuv$otfZNW>FgV9)uI$u0I;r)NLk;XOah+$&{6j zIh@I~dz=m5rDHwung@dA&&-I$!`cTiGz$E zEOU@Mbip8Y=cunmZ4Xa}?Q(q3hPjSwsZ@rJXxUUCRN#g|l39)jDh4n~@!dAw9Uoj) zo=awq7@O@^5Y8lpBO{y^#1@odGQ@zTa}@?vyG*6ie}vuq=r`Pz>c`!gWHZO?up|xwN+c#;k${#skXRc z6t)NqFhL}B9kbUXij?NvtVIOWwLLn+P)$IzLeT#Jqs_D^Z!DMr=L7?cj(G3iy>)gF zyIn?Of&@voYzTIZqaY6a2^O#AVPfi9&z$1Z=t#qhH$Dym*CHt5snkhH$kyb`$P}pQ#^z{|W zUEIC%$dN|&vD=W_hIcW~uTDp$dK~xmS8?47XI7ORnp=WaMcjK5G7f7#>dL}vR^B6D zF&oZBVxdnx2sz`ZHJquW$H~bDq34frsM)Ntt;>M5b4^}eM|RYV&B8^eci3j zTdxCyUd^T4ScoC>BbEsq1e492%+cg-+yi3@PemO#^v!r5hompAJX1DppxfkJJ{6>1 z*#kH}pjWF)HN!%HJO&Nl>jM(m91IL|!94vvYN^MYp)iYaXK{OH9n_Qgv%TU=Dl*)% zeDX6Mt&hz1>T_7JcveZ4`bE5fTwG7&#-!z=0|h}mXM=!FPa~}^k9yaaOSxJYV}N;O z?ud1eddIi!o_d}*>T6cxS^m$CNhDDtt9+pe81y(iGtHZ8ypp4^nwJIPLCvtjRPObnAK9#pd!!StOmCgVZS}h3BVA^=Q27yLsiF z85oHN+9R15F+3cM{o#Yue@f&$SF9kC(gXXuD{O@lD(+Hx^VbA`Ksdn z*tyNMBW5ee-%EkqZMvD4&WQZ1MtLCT)0*XV4-HzRa?Ll9F)X_wisVNtFI}T{31N@n z&2|uJb|{J@j^N(Ls(JJ<(BEX`qA?_@xcNr}bN>L= z;-Im(`xTrjmS|>a2idOVjL53PfC}epE>1{3p60cuo*`>2QXB#qht0WJiS79R0G=yV z7`3sTMz68SXi>-gpk!1GkvVAMEZJ!f2R!rFf$NU7*~bW3Jk&BQl6=22lN)e&12`S) zo74Q5Jk$`a$axk(CS2`ca=))5>09CMB(_#`NaI-*iY%L$F*)Fz9C7}0S*mf4#?YFT zje8}wwGNZUrfD(dszx%zcK-nN*7>@-NaYqs?AvYCZWbmhxenpT2N*dc(Dbfom|jmX zv6$pAl^+Yc2j#~d4_bTN-A^^FakgFI3*|-gZf<~JcdAynRpqhJUy;2UQRmAFC`>SI zzfZ*GsSJ4#p(bhLELK^Q?(%rZ$mb%P9G9CGAqq?Y`Pz9FG7lt@PhU&{)}mX6D)BM- z9#xVsnIJIE3H1Zt{AxKGXB=aB8EglB0Zjo)=t@pFZ9dHH*Ju9YxVrXWy zpL};nBV`ewz$cTxjQe1F^Xo)gwcWd!z}X-hzEXHTqP29(KPleQC%cViQRGWwX0uFN z_*4cUV4exj0F&B?sUDmoqAo)%y2}hL2?&!(BDb6Jf_TSLPCXB`E+K2E&VJI%6Kyk+ ztQS1<`qitOSbucSAd!rXmJuvv*bZ}!rl}bg6DW-&Ea(^aX}OgD06Nt^Q8#8-F{!zg z;#H0`h%t^v-IgPsc;h|040>j-+Le#bL@jO_Hu;r|VWT5!55!~;dlO87W1bd{eXA&o z@AJ4f@cswZriV|K-_DD2x%otBCRrn5e(@{`Cmn#}p0#(nGo0mO+*nl#p~@B>Ud-SQ zox5~A`+8ED9tdvDx*%2!i;cmVn>_XDf-&^`s%3dnQvv&s#rv@nebqj`-FWw_R^&>) zPn#N$f7U#EmpS7joa6lUqAOE4#mSD1rI5*;voMSnm(2{U*voVE{{Z!#w6RGPKzX*( zO6<5qjzFMDPks(YGr+;*bH*y%u*GPxOB1 z6-hGPG?7TUyGaN3hnHaGn8vP5Ybt}m9C8UNN$JfvPF*6mide3h#@HGb4Y-arsW|V& zJW9+}rNhcySV-zg$nB1wT#xHfPZ}-aTuuVs##{tdAOzs&&}YzkdsIp{MsQk|?wLx; zB}ofJqy`I}&5zEjX~kMdTVuw+jma-04_sr6`c(GrWog){V=^6saohmOKh~w(zi7Ae zBmK(8#rkeC5#PBL&m}HyW2r{NUF4DW$Ro}fPnR01g$F!(9y*VIT5RofphCB|aN4_; zYZP!{mHRUcXDSKCKfH59j`tFXq#I;l#pXa2LV>^wj=T~{>-^`jxs9ii0}@Sh1-nS! zX`CxYxF9eC0F#4&dY%ByYZh|UjoC?JAtrFmCB!VdVnLnR^r<0|A|Y#-pX~Ge(imkh z%mM5h1gZD!Pk~d(mPtI(BFP?Al;no!NC0uqUX@W~k=tZ31!XPgNcRA#2cQd&&z|D0 z#!3ps^07=Lot|WkB{)GL5)iu(78@%}9Dpv%RX3s);9OA8PklRjoMZN>_ z6^!lYIO91W4!r(UN|HHNh%&*)%-n#(u06TW<5r_$%CRhlLFT695i-EC5uaX%^Tkhg zSymL88Z{^t1TX+kA1NSXuXFg)t-`#MDKcD29I>8W8HwsosXo;lYF6TRND);;WQj_vNE4l_pKhG@r>t*q?n|s`D-F$_2Yx^L z)aIK4J^PTvr^}QmWpmka{PXKptj%GpMN7Rk<+xjm>#1&cuaxjx`H24j-!A$2SRZ4a zc^Io9;oTy@vI8jE11P~??{_1o^Q@?0wzYYsnbjI)KQk~q9CpDV)yd$KYyl)O#{}{; zmqEc2DIY30d=PYj6Y>+;IMqyxS&#v6w9>02nNFlsU?6C_bf=5F5d5UPs7mNU@z z>JRBmTawExGRruES%XOVELp%f&PdNw$?2cMv=~mYywFaKBupCO-B6Nw48zT zHC0s|LNZ{ZGeVgR#riQMbqAajtpKQ?w7|QX}~x%u+fH!6cIfMo&2R$j|FoH>rH9u(rQx zceq<?R*B>rvnr6loE)6<$Um(m%uN$4dtq0e zG>}MD80Zdv8kCzYMm>f`A}yG*e3(9YApkEK z!Tdn$Q2Fj&J;6ejP#K2|bNwpb?S^Q}M{gwY#wPP}Rac-O0iVXI2T9-(nWVM3SMrt= zRSP71hGIrYJuo}&Iq8blF_I=!?;^#*-9`SU=TDN+6_!aYqmWGP&UZ05JREQbPg9z& zExSM?GUXkaWO(0(Dn?Y}+#Ki7`_zRV(H)qyw(GZJu~5uUAd&7rol&@%m~FzWlPB)n z{Mk9rPhp;z{VPYJG*N;yXLSvPG6$IsOEC%n9eKbVas4Va4r2m&(s^6uEFxIsAxBaa z1tjN_)RE7+mPsNO^TjR0GlmGCF5ska3E(%TeQF;zc9EG*^6c4Dl0|J8+3ZDDn=8jP zyo}#x^9*mDuRI1eEAFR|eW;7fa1mGT{IRO~_81hcl$1v$tcfEgLqZeMba!;k^o zLFYAK%sja*)*Q^tthWGi4oKPuzDMbf^;8cq817^-qG5WRfPFvDdYBS2Wqd~L24hi@ zM^Dezr9B5ul5B}1k=5mp?nICvoUl?yeEJ_@OFZxgj%9UFje-M?Pfp*~roKDaS=?FN z!D}=nyryx>V=DOsbvPi7aB3-s+Tp(v-D3slq6V zX{5JbEGP>r{L%~(s(+VSxoRNe&l&yjSI7!L>M{NztKMxHL{+zWM0i9~BCC1~^NjlQ zQX89vMvghHgcHbrcjT)wu7w&3cbJmezlh` zn7MB)Ae~oiBc5_aX8$9vPGWn{3Q5Vft`J9~c$LrFWhF0X@cjD@tnz3lqF^EP#(G<3*81Jwe7tY*vO3LmSEg)Ud>4pPcv4 zr_!ajia;G9xh|81&9~Xh953+}`@O&bbJy|eV9-p^K%j3=n+o~e8t_3pU;;@P2eJHn zjXy%MvW0)pR!0CMFCem<1Cg zYUlhTX5#8^vs}D}0JwXF5t7}`JN^~i+u4gKEv?Ec!Y6icI3an*9fyE{P^^zL8FN+$p}kK>SPQ? z8-va`oqEGNuR79#sn5D8GHwKZdkJ?CyVg3d-2ML15(=~X6SMWV$5%4D>$ zjilPMyw)+u&Bi|Q8RC&_E#sMjM-oNG-!3(cRY1V`RA7D;zbaii+w$I2k``$22yA-P z65Fzcjg%rhfZ>$w1FyN_w3SG{gmcd44Xz?$x66 zWK$7SCee;L$5G!O&Z=BPu*L*wwbfPs0J;zO;-$`3G)_qz4VHxvy7OJ#PSg9m4YCI4 zTReg>>s>{*fu}~TF}0dm(SCVMfn&hW7{+%GUvcSLFhy*V2T_R$Rm_S;dgJ-_tu|R> zjL#z^QIvJujg?`}LB~$~A8O8C@sgC&+~MwgKO~Lk7)Xjz#sBnm1rSRU{ znatcOx!xEZ%zN|n73=RkwY+5m?kI(WvB3keBeqAsYUZ^GP3p*j=Zngne(L2}PbUMP zmy!t{{pu1|I^ybbo-ccAwn^W~F+~)+S0k^}*0H2U^B|R2;FIPnjHzEt8twHfN$zGq zP^?ASNGN_&oM(^1p^wAiuTicW_b(ePO&$m(eMdmq{Cm|Tf^FR862=8zFCiZ%bjSj* zQge*;$4)(|scjUJ&2iIYi8N4bx*h0b_I514Kn%8{l0+%dZ0Pf|{E$sIr*o|PdH z7*;6>3nuKG7V}qU3qntSzPvT z6=~C`v_3=CuIypCnl-qJ?s;xmqKk3eyBR70!6ab&aro9gppwg{M9{`sN1J@5lkVd< z8T@l!MaSUlYwM|9^r^=fTY^B0G3&t@JZJojR)(+Oi#W8Uu@>na+ma$72v$;al6m=u zOn3IL3cgv1oLrC9vfS?jm(CI8eBUGGS#+7Bw+-g97^CwVG8=0%b_XXs9P|AJc|NtM zT-w}RMjG7t3c-Aq-Ih7Y$T&T^e_HzkQ1FhT`YpzvYa+^k=2&Nxsn09Bfz$%n2iF_| zO?=Vg--O;J)3n*nnPG@*VO`f2%0!n6#kUq8-T>|6jC{#JWv`EV^~Zm2_c`d~yP0jd}aL50$yrP>9^7Da&Pn-EX>1+rXMX_JXd@w0Vk;_LC%vF}QHV5Tx*N zoO*Q6o%|)Uy^7227fEGzZqTQa(}#=**ktjyJCyzek4{V;H1Pu+R^r3$BgwG=bnsl_ zMn5ws2mJn3((1}`<-U)|`TCKaNIi6Be~r9dKD9bWJPnVLgTE?d9YXVvK>+0Xk9zCA z5Shi*&Y^VTKix9#k}%3JK_7cPd!K)L@mqPK*L5hZq_=x%E+!a;)2v(9${#dhR% z&m+?Z+%-Au{41v0*jd8RT+0Yq;+2SY+%m7!V<3zkhtrzqok;y%Q;G9=#TcwNEMidj zq2gA(y3;JQ?Li*mE2jx@9z<<0$SOBub~fOTucdRkeAjTrE#1}4n_hylf28TE=&`p| zKz{Ea9G`!nt!1G#<=W~x(ffK@%6ylXY@1}xavP9A^%ds6H}OL@yqb2OszSDCk*(O% zRhX%4;66YrgOwy4a87uxye${Vk@@y5x=?OWvGhileP??Ogt5yczh_orT>^n4F$F;c z?py$Q00WQ*89RET>8$c!wx1>8wMhKgmN3e@j?uV#9_Nmg;_z!nOwnyD;8uH|DPIVF zW0TvrHM6H{*7Dq5ysq+TGuy^u-IbHf#~`W32qcVGqeiVoS3}{kxY(>yw#OZ+c&=Ie zM4EPjZSE9Z%LLo;AdNviI}EVx(GcJiiUiW#RKWy480jxYevRv-rB13hvF zwRskwXW_pO-#qCAZ+ReTvmp_-3CiO=au50Dy%R<8wUgX5)+UPe{C}<9S;lm0 zO9&x10k+;lJ2Z_MJZ@9RCnJN}xGB`5Q1de@-i2NURUkoNTw-CXhe`JTYu z+dA+2HNyV(0TFEWQ;>+9kr=}-XvJnVG2jxPzOxpfzN)m z^7P*rq1AO+?3CO`Z)tki*&ZV+p1JCJU}M+Xyz9h1A=W%XadCS*^F7FtSeZ`EgP_R3 z&Uxo2^5P3MST00qXo)Y{A={m&Jqag04o3s^?OfHM(pI_pR!v5mn&m!=i{eGjk!^D= z$(AT*MSE!G%CJ-HaC&w=)kjzO!DDf5u|YCSmdc_@CCAH?o}GC0uRGQJBjT?W+udp} zsy+UfHS+z1Zf%w+qsYisB$mLyI622W^IX-}!hKqJqq&G~)G{M$TWL+ilQ|gLt^n%T zJw3ha&YGzic^{d#nfZYx|MwC19V~rI3(vFV;J?X zNYXWJI_BbId6$aOV3|ZryT!XOBaiN}KTd1rZy0z+{{T<$M4xL+YW6=g_l#MN2Rj!% zbB<4_ACEWi&`85fgp22yKh{E{fTuiU&ADUCWPnZp87z49KDE%zdwruzd8Qj8g>&XzM(WEW^!Z36AFocBHQ~Pwd|`Lu zdx)Y~4VC*&tHcKgI;p`wFgeCl_0LN7d$!eXrMQdjF__f;?kNY7LXM@29s&31iuS1C z{iQx)A%&bIqhrdvX{%}aZ;BsMvNy7{=?}`F#~gtM(tcC5SmzvaeNHRUyg8=dd_Zf$ z(b-2ImAmZicml`N?T>a@i06#wr*mFsPz9iKpk5QK6MX+g$S=%AIMPxXdi$ zCEUpP(cu{U5SI7pb8`)xaR#}wo-oEn1UBYo<#C=d#tsd5&V%t%YsX0mk} zeW)&_a@^pL;UMQ8{{V%1mFJCoCF1Q)R)Hf(;J8(9vrC2@iU9OL3%{Wm_ZzwXb+r$Q zFMKO+GQ^J^=AxjwMTtF2#aERg!iw{Mf)GE(j~vuU??$ zyv6=8NvW^)eDlEsEh_JmP_`055`&%K5J)OJt`A>aS0Sr-)=9Ms%kgp*?j;Qren5p} zzyk=Y$0`eC@_9MQ#ddv0ZEBA{8Hae7+1lsUI`*||XCx}~S(Guw5?RNn2I8WyI3ow1{LG+z^w1x#u8s$6-)GZQ?70H=|Y2WDv};-PlST$g(l{ z$eBS5Fa`m~KAEbOHQ4yPW)s-A%OA}9Vm}?&x+EH>k!=J|9BB;fQI!~O-Gk0C&rbgQ z^%_36;dtR)L_-zI?fI0dxGT;$Y>&_S*XJI!s_I%r{E*FXt89`6GY32_bBrAE*S&gI zhJ1M*KF0EWnWts)nr1Ajr}&8U_8*5e%`7}zUb>$>Dwe5d1%H|LoL(+S$$^KcdPM!fq#!DiVY5Xr!(RDu!+v_@q+1CEgPqzuS zNiJrPD|+CfmL8*z#)|EHv}QQtvtpK-*6G0nZRc4 z$?b}U4OT0=ma);|5hb`*xsK%oiyD^dI2al4`qx6jxkbAp^_-_CQcK)9O+#4m1k-(w zeeK&pAuW4y1ae3Yd0@O}9lBL0d`YddLp`aw(q@M02;Skg?p05`Nf`h*2jAxP=Dk;4 zo9vo=S6Y-BHJ!9%vn7lYHN=Ah_mVRL06hYZ1~cEDG;10RA^yu_JeO+ABzF@sv|E7$ z212JliT+i|QV!2VeyfpSqZnxfbeeaJb=JAPwz|{)-89E@>Q<6Svoi7oAqg?z!(_4N zDlvd@U0QgW00g%JOHZ-1X*I5L%*2dz9l8_HeihE?ce-2KU)lyRwd_%}yRHfHVh2+t+HQJkE5V*@6{`pwySu5|chRhM%cnBx7}WB{MU1C#iA*U$6G zeW*N!*4xQfe=S6e0=o|Tv4#1+AbG7_Ha`?v{f_2oWsd66ZY}0IZS;)@S(L`gN|EL% zQbFu;c)`VZQ=w8)KHCGs5u8)G^nRJ*=;gGCqd_gqW8^I7J4wML_2aPV$Gv(+i{i@& zmU!+Bu!m|${{U)5U8fi%wlnX~t$e|2s%qADHnw_owUkEPO1yWPNRgT^XUHnq!5s9@ z7|m?y`p&zV%yyc6$Dbhk4D!a&$s;e`4tEiPF@dxZ>&--I&N98u*>GgBag~;ysQY)r zJ}%JiqD?vAF}$qGW%5F)9Y9mp@gDW>`h2#xR%soqutS0KnND)K`>Vmh@6Vr)sc;Hr85s^DW_!atRH~DP9Q3Cppgsy~|7S-;6D-&7`_aA2Y^Mdl?um zG0AmqRE|agJ*%n|udg?axZ{?+j{}m+&jyh~vMC$(^hxCv=L$gJ>;Q z0P&JYTpa%ZjS%^1qmx2a;3HngeXdL9xptG#@ zlfc$`exdUz-F0?WXjpO?5OwZy-N5y%c{0k58FCAWounX<&wj)o^VX(lRwEVUP7+yR zB3ZWKqsb#2bBtira}2Vo$Q#Uc*^)yR@BK{;q(P@|ZyWyV@H9+8@`{jIq$A|x(4PIh z4@$2kqd@yoVIwjDBMA=Ez&m?#4+Q&ua!C}sY8+wQ2mYSImV3a6Ut1_g*>?&-m3Fv&?cV3Z@{z<#qXj_vX3{ zJi{Hlvr2b}rU;)Q3KWic>&FBC0M%4Xmg^(inLl(~6-~S-IpmO}^yogdI^5%}DXCbF z2oma8-c>Q7bNBGPbM@=itzKOm!e>i=D%cPj2zIil2LNE>I0GbtPuH5Y2iWZ4Rk*vh zfnGz*=-4Bk7lVv-&!%dWVHqTqfsWrTvT`>DCph49{{ZW!W^?lkZsOoga4s$i%o<{{ zAq>n$PU75y&qLFiVrmUNf~qqlcK-l9#?@kElRkiCk-Hi8HC8rfl1+u#VkAg`3gn+o z2j(hUS7-~iSpWnqh^%)p;B@SB$?f^nma0h>l^W{m8Pu#%Tp(d9XXU}b+@KN~MW^2(qQ)be=A$K%qO4ZPB-zuFmD-MsrmVTJ>t>G@;VnyqNS!s|9C zQ;-7;;k$pIrCm8%Xzfk2R%sPrVdXT2I6Q@xHv}YL?)gq|0X~&gTQSSJ=H5Ya2k!17 zW{?rj2N)mzy1MpH9kWD|Z&!=}6;u%3r~d%0P_Nm?n6X>W4ECwAVIziRV58?HTL3me z1E>T8&2@W74$X{;*v^k5Ml!pyh~Y^-gWU1?{VG^iNH*MvV|CiTTS%do<@Fqc_||by z@k&jsQd~5j=^tq%5(h#sa1VU-=suT~rYIpQ?+=u_AS_ux&p7ntlf`E_HftEzk_fUb zuBVi$NUipSSd^$f`RDTWsAi2Jb%BW@W@8c9Ra9_3{{T-;KD81fM7V{pm^+4eQBx$b z#~eRt-#dxEblys0N`YF9G*o_G|)){Pb_fT zTww%O_KswYk9;?9IKjs?dg4nMS!RX{c;mRA%rQczX>4N{Y?Fb;PI`J)CD4z~WsXIL zCnN0Wp_385w0)4xhVaaLlk7$>%Z;FaeSn_8G=Uy+*Oj%Or`y z1_16E09A=&oHkS<%C53R7=~Us@A?m=Z62la+=XQmptwOQ?UG2{Wrb7+2M3&z-2uVr zo}AUBSec4OZXprHxkc1WhDO_-;A9-}_;;$-@dpz$z%W^wL!7Z@$>-bV$2Dd*yOQR3 z?@+vvXYBGczGEDY`RA{0dVUoBoPtl3s<120nB$N)Rx?z~`nt>Xg>+G*@#-?DsM%w1Q$)rDNQXLFXKi%{e3uCiF<5jF4uv zO~eH~0+u9<9_J^otzk6oM6V)bhB%>}uVGhvJC;@{C{|!bKwh~Va>I_EwN6VyzEd*X zg_DBj;hHsGql4TW@+!em6RBv5mUS`j1c1H25B{}YH?K5q(oCjE*sy5^OquL|`t=Dr z7{-%>W>}8m2-0_s8B$H&SQ4uok5CC9`x;BPF9dF@D~QrHf;)Kf#mV7*gz!&clTVAw zfyjVG51qU1LKS6cGBAE%FbM}7{#;dj`F>(F>mJ2ihR@#U0Q?SeYoaiUUS_E~>{++k zqVnf#QOy@iWx4}v5&StIupIR7inS%>?et+UBx{F23rldtn6FXKZhxP>Q~NZMKG>vI zg&TFly^om8F`wO&f~RrD;huz4mZCO=-Nd0}8&s7susF!dwm2kU_aDw>vAv;T5pZY<8j7tDYs80tnnYSWnr^f3fqyj zn1VJhKy&KYAI_f`GQ5+?KiQ&alwfQxZKf6#_nO7b0g*o@=Dxs?;GqFxpggml&tj?@<0HiM7Pp@vD{;HBY!*%mJA&IfJ zHRuRG(xX>}SITG1p&8&(gL5gz9N^>HqK@XtZzK-^i6nEjC5eKpncOg2s2;ieaw}Ob zR8y$gqa?xLxt3*(c zY2YkiG5n#4$I5fhuQ=&TGrVv`1Tw6mHdgbQ0|s1RZXE&j9V;lQGC8KnBbw%8$!{%= z?MMAKo=Zi zigfG*d+nrc$^x-&o&Nws&1uNwjUx6Y4LVxICzd7>yM47;@Y{2Y=LfcVrnI*uQYjh% zZg9S2cO%Tn&rzP3@AUPhhEzwEd`p&zeER_*Y^eLBDL4T0%|R-g!tAi5F%L040R&8=#iEiV9l7W2g?$I8CRgn<0?m?=i8dMGyy^y&EhYE(y_c4;6`qCmZNs5s{yyn261 zwZ3$UX{_!p;g;$qiRXeqti!m+q2wHPH4HLKD2CA`^1SlCY?6``HhP=_Z~^Qy?NKgs zWuX<#lnU93>N}SvP4L3ZCXPPE_`>cv!36X*8p`Q!9E}WuWre(^f>9iVW2a0j9(g~H ztxFVdBvHszLQpeYZfviZJ1OHh>&-_nMwvu~yqSXGlOX3A{QFlsr8IK5O|nrNZU z%+~RV=6UxZ2c8aiAm@?Sih8e=X*}(+6#y>sM%fs2Y}8ZR%_B?pM}*=oRzrZtu&cKg zt#J}UN=5c-Rd2BI<+FY5fHKgI30!uYPAfdC-Wwg5G1KB%w|y<6+e3{cm#8d=e;?M z7Li{GvA4?eS~%EckVLwrc1)KTx45!gD!{h&Y_CruJ0^L4%LsI-8!85)DhatADU!`c!DO{gz(M&ML6A?M-1NKHJh2($0Um8 z9m>oPAe2^WBFE`mbtGhg0+fII!7ha+^*|pja4Lf+mcD>LC7Qg zDIV3Oc~s6Lh=p{(+qivweY?^~htHLjQ!z-a5PZNce;@K{($DtAiJV2|ESrF0Hm*4t ztkY=1Rb-pcWxC9^_X`wFvS8hES%~aA1B#X7w(_?^73P*{JhW)W2?HSIfX~$ZYB6^w+9#Bvqzc(l z&jT3$06F%q>Tzi#VCJ38MQLuW*hFK6V})dMD*zRHjGv}4{xwo4q6;48S7df*_T&tn za6XkS*Vu03g%#Pp%&R5Py0!AvW!=C|q1SE>t_~&elEtarh7qy;pc7`$BnYr646hXAQY?k?U8ZNN#Q#X{Uk&g_mT~D;=P2 z4V}5*=eX_lrij$De6FPws>FZ=WgQ!iIUb(8^`_-vTw=Tk@kHAq5uhX}0aZzL@`sXk{L3mSi$E z&~SO}?fnHqsIL2ix)jR>`C>C$*!kz1tMJPVN4qcpu>f*F=B(U0v~Kdl51G4W1c9`z!DRT5Aa9$_Gr0Q-f@avE*ZdNCUXz zlb)3!F_iOy;TBPhkDHUn9e=~UM#uX?=*b++i5Wh2&>3WIg--rdF9YeuYdl@M$23Jt&2Fn5yfC_;R?jTiA28dH0LMM}t5P5nyk2@n zWg`mN`B$b+GHWX8-R+b|G>fv~yu^5ASu?jFZ^8LabHV2v=8f9BH0|SAcCVHk z8OB%wTt8ueNIByt*m~6aV>2w9A~M8VWBGfw=j+>npQTqqSvEx?#%3HUkU*0ix^(8Q z7@~qulFbQc+RNlj9hx)UyQ^*lVESjhV@Z3+&TmqqxWPtnE@MK_hJ(xl8QjF@9+)1P zrd!=l1+o?fa*}P{SLR{OT)dtnj@&J*n?lHf?g$=1ob$Q41A~s;KDA5Ei^(k)ndbSe zw71Htxb4Rry6>*#}Jdwwz z{{UOoqE9Uhk-wQW%MUVn9PVN|^*zs8hAX6+=2^^a*AvJRGoP7Px%_&crBn9~7DJTPN$zKbHcWvcifbo!VCWTP4d0)mW7r zu{gmek;i(0vn=Lx6ETu9sS@NgipPPDpq`bBsXlFt=Pp?-3ok9aF+p;4=`QEBUC|}1 zfIQ4e#&;us z#~JIJ2^vci#BfSR+hgNtPzz(80ncw!RX)>mB-ZViS~X?dLtv|QAdGz7@(o9gvE8gp zOvdI$x0dJ+EUt3DFQ_9uPj9VbB_{VR#@$K0w70;7l~%!ZssA2Ij(RZzDjQKoMtj6lDaC~T5_Fi7Zn`&EeMCTU~pNAWg6Zcj{pb)vBn zy|fd{lz!;Rzhd&ljIqzR6*T4Kk!}e6=?8N40-F>p&p7#F@*r|bAz{@;-Y^w8tMy| zw@b@u)J+Ag;J6L_+;9O>LCX$5DzPQBt0LP-jT_uXrbS{<`7F5%IuVd^2}wv6R%8LV2yOZMLccEKzjmH@E>s7wav9dCRPu!0%d10G&K5ls9J+W4VEej;=vSPtR zfpV%BuS48(^{R}W&q~pfEJt$`dw$BnTPj_#_g6g*b5#->n~T+JWZcUeFbf|2?SsG` z{=Zt0nS;x^)=h;l8I&@x=cokZ@v70UpBhON3u?QFLlngUTpXS;&N>faS9Wn%q@wgi zsU%i`e8ej*eqE; z+V4-7pkt6v*Bl)5;}s-wEzEKO6Ffpt+nf)*&ja$$KD6t5k3J=y=qkk^`BdW~Fi81_ zW0BwM-j}nnyHar&Zmrhy&S;5Yh>ml$n2s^)k5N;}8V@pchE+sSh+W3!BRR)VGt_6) zR3Tw=Bq@ZA6f&@fDi=Ip}f@1_x9=W)pAaNy${ z=dCwu-Y^kQ2~i*tNZ_*LzA%4Ut$?0;N4bQPFf6PTu^e!F9tSnF9;889L+*UBBymq_ zuMSm&lEMP30!RRLBmfRib5~-TCUum_=Cmbzye8!bIpiFIJ&*OQ`NZ!g#J0M5t(3{A z-c5M3tc0Ds6&-!fLCD8LnQiVx%r`b^GeIP1tu>-Z$s?&a;~hKToOC_u)VoJ@IVF8d z6G+z=CRpWFjpQ#Ri*B**_S@L;%|KQNMA9|Pzip0D_E_b%45M&3$OIC(9Opg#DamId zv1r~&0t2xOo3H`tlgBu#QcXOL#StDQLIUj!%%da)Kf-r={{T9|+L=yT=x53$L2i;y zGsd!(h6vv(NhFX5Y@UA_nJ+D)FhwF68C|jzjMb6lmV1q?-)0e*qg6X&W5FlXatAzQ zipwxV7un=V7|$itn^?qH5=p@0whz*&JBlf^UCdHLBNv4ul3lUxi!3wO<{aav6qD9lXmXBUL1C=O-YJar89Xk2ZLu@?kN;6lPR&h)SMw{>eOgjw$h&O`%~U zMJvjJJ;)dp_2-}e09`U=8xzNnE$t)oyro^hd7mq;2@0dL515?#`q4D<8+P)De?CQG z=c^usli!Y?{c}!RfRj30v=FD0x;66&cL(^0Jvqn#b^@r#E~QBR&jQc#vbx1F0x~@~ z0hEmM$4Zvjv?U^4u&&2Oc^ybum;$Z4zay{s{V65$12lv8s>QRD!isA+mUWCPLa{2o z(n#ESUU9+eo`0oS^8$kiOcDz!_ikyCRy&luqZ3UvzQ<`5SdHH)Il}-(dI6qlc&($l zaVP<$jSkRotg*4@KAAWa`KOvv@=Rh5gKNibs~!eEP#5SqZs(KMpKSypHMmSP(Z zRd#{TJu~P#o+@XJ)=45ixGd4{XF{L?0UfeOIpUct&erZgn1xc`Dv)#O?fClEX|&Gj zO7J{rTtzk^Xi_l;`nMx-k%7-bNaOJ7>r=wY*Is4bojYkUfVZh{bsRECvS*0S2?qfD z+fFh&nntyX*)6Xp)9!CH^d>lx*AbGVvatjP0E5ncoYi!dn%unXRfL6O0P_2_Fd+E=%EA>SiL6o^sA(4hYS z3i^)!09?@&E+i9qpX)wZP=W{;;P(1)_|}|oM=PQMMJB7|Tlc0fR|%K1)b?lb)G5>MBce#zTSx zazrEu_}mFU{bSazZH5K&S7@3?IFHXQxqSfb-m{X6HrS1B42lvbK)zC}>ZC9d4myv1 zdG)E1W+`(S03*h#psq@>>yN4DkAGT%_gc4Ai6XL%FwL?LEXEbjWjH0240ZSJ4MikB zW&zZ(-l)pHVPaT}p1$X&)2=gE@*_DrEs1TOVzDjC;aV0DD#%;q2b}T2&u{Ul<4e&l z)R|TwL0MOz1m~xy2bx5l-C~kCCW&v7Op9pQrI2oKyvL@~)655*?CS{@pqbS(&51VYNGI8IUC6G_@#TOJahJr5jX`PPP>&l7nqbsTZV&9QC}lOfL`NC&eM&tQ4aQBz5yNEO4($IP5as<~w) zNCk&pag6iQs9i;UurvXDmWwz@_c;e8vf27@N3XSP$&oD9i@D--R+8wQ&ZKk!dSSA1 zdhjtsFf6l1mT<5V?ptVMW-QV+SEBMxPXO`Kx_Qzomzfz>5fqM0qVGalBw0ufpdVfX zcEI5A>sMxx;yz??xsg!f-ZB-J7(MVg`qbAg5_wGwazBwIYcn{%~u5Vg2PxRyq8^TFjDXB_|;&#yHc?O^XE z%EKU#Zg1a8S~(*)3ZXHTVaYi>f;wZBv0}?_s9W6?WDSOiu*N)N9=wh!E#hXC$Yemx z^A4os^!EmuU=MoJ;5SI1Ne?H&#hUp5?d=z1*Nsc)QI0D+>Wu8Kg4$Y z*<6x45(aoCtCwBKX;_|E?Uq?*N#pZpn6$7QmfXD@{J7^N3>@%t+N#^!EV7u%QyY@o znSNl|BN_MXD%AVsHr`~eM*Ik!gA`vukKrwogPydDab^tb8Z2TdS8}lnlgM_Pgf2CJsV+@w+()k35T*Lv~;~;Q&=QzpflUUTJ z2{WcMPAsa$WRl-&`GVgJ3gl$>&#p6!bf-(bWOt59v%L9e6R7@FLX$5n*}PyYa}uKw;;ks=`g`GT?JdRB4ei`|nK7EvV5iKrwi9ncA~G4ikjsK*17f_{VE zo>F_6Bx&T#vj*Jcl_Ng>zNUy`B6pRES)hk*))^p^oS#r>#nMR{6=JB-{ov(Fll;2Z zOPW#K>x)sQNe!=+919%j8HJl-PKBg)Yy+F`iIHpY_Oea7^tk6rj zmge2VHV55P!0(*&;~jHOjKOarv#JCzw357PT1jLhAD;kc&{CA7CCrgtOAEt1OvxCw zk1aEDOEL7vaqC(H?JX;U&AnPFgD49cf=O)SgNz(=`qDzq#o-StGNfiEEw!X<R4@eUGhFTc?Ojl1^d_z`ThFRmlGUmSA!UkU%E`zr9u2J-yRUDge@j zU=B*{#z(F`ze>2qNj(QAp{Um?`{8*lqnZ_9@mm)2JiMKyvysT-gWIQCq-JPCG;f&p z4>KcxK|KCdrDqFEGD~jB$)fEG07*OKGjBdjDtP2ZzGvk%2l5^&O-ve z$Fa>zi#+*7$?it6+q{t(rI|x3Fp?$QNgcX?Gm-h6RPIvVaV*ocaG=VrM%Kyap1Bww zom*H^P_Zq=zmQaUj~O9hQP(^J!QkUG&nxWC$YJwQ%K2rNELibcQ>8XsAj*ky65<)H zW|9e@pL9ehWn<4>z=Aq;_xe*EhNyr1&J?kDH%dV zAo1!s{A$}OpZRF2B9Hg0C@jpx^ceQ%pGr+~v$7KM8eoN`XI6O8CZS)kX^0FwcuI(ij(;$``i*;bZ!N=5gIqZLxT4a`Zji`w?TY}LR zDj2Bb;~;)sy*kp`?&TYNjmMN+VTk9G{uOFi50pzYqQ#8O83!k@^~OdC`qGSL&2l;U znU=Eo&P4HJ_YLO40O^o($jCf)^{8WzsyQ%u*6lE8Rfh_|@P7(?5M8@m%^cRLu!3Xq z+D4Ff0PqJ~@;e%_YXrbYIgJX%8n2TRlDl_uPh1|~m1>@#ota^hTSz5nU4*wJY!Tz- zZod7qRpI$%mF`ufL}gfHU|Hl+db0C_liMSXwYlZI@kHfX6BD6ZxQ~Cb2m}i(= zx5!;lPGd0z!(@PRI{Md2Z8K<867nG`BrFMn2Rq`4iZdzfqMCmW2HokacH7{-b)?R4BR|m$L0^e9!~|ABR^5v zo0DN#+?FCFy2N;oG45%J+^pUI0MDgrLo{*4xF{1NF$0iEApZa?=bviEQxBUUS=kIB zvlA%{2d_+Wc;nKY6~vjfWK!jc^Gjd?IuG%#DM4K2bCg-3C|8a$>nb^gL#&`~EC*gN zFnazpkxLA2o?15S4Z*;WZ~7iFnkJ2*kmba&z|Xv)4ix7Y1#^|pIqCRQ;8^^{kzZpw zb=XSadiL*9p{PnqNQ&Wp#O0-qP01K840+odV1PL2dem?_&LX@AEAqA&5xDdj<2(!w zf2B<|#EK-ehhYKK$nBQgGDjTXdgt1ic*YmEiWT`B$GGx9BN_bbSSF0Qnil%q+{-da z1*(Q;xOe{mR}5p{pO-z(X|V|+xOp1ae8uAu+uDXz+HN$HR8bmOm2T3O{}9%gYOpeq;wiT3A@&Y}*n&Ig$& zxOmUZs!VHx(4K(v^*@DUCGQ%pNS2+Hq6ro-!B=!)Hx*IAB=81LLG`NBg%U>>m*xhD zdCLhKSCgC{>-tr6GBwIax!x(@+#I3Xkb9n)=b@{SOJ4teBawOa&QOt?j;jeNbf@kg~#O3L3hc{_j|F~G<3sAG=aXjfr&lg)23PcZCN z?SMZ#pHMOD1aicp@*v3aG+|~*6=W+ONd#maq>+q{NXY1MP{kZ^sGeCRNR?HHNQsg| z=m#90ywu7!E807k2bN&-CJ{O$p`x^T0?5UA8*|)aBkAo^Tfo!iN1iKhG!;v`*ra&l zW58wzHxM!o1!qejAQPqROdW>@&_iy3>4+;$O0POAKh6Ey{AF9&mHh zrUpB8q=rZ#VzOL)p<#ieNiH$EMjQe{;BN2f$Kg$i+D3*)j_x?6c{Z#@B3YLnqmF+c z@zOD{RlG@Jl1L(v+^O5Ru?#mVoaa8+@AapoR}zvDgi1?oFhmrp^vONyJ7;TM!bS5F z0k^pMa5GnWeyrc#9Q5_)wL**&F>dk}+Hl3B$!(}Ypg3ddGw;(CEMbQBjxdWM{n;bsQ|a}^ zPYt5R+)n|FM$FNhjA zOOKT}LxX@w>G=E8qq(>cMHql!r_8Pg13hV~UImO9bI4$Ws)N&tmK&9y%uC64&l~_N z+S-)`bCJ7~&p=P(-hnrE6Ui)@IED~mRAoS@7=gwWK<5KF{QA^tU4lx>AdUh&!kALW z&>ngE`ihq3)qz5+U7IbnS8D-Kw6iEhnjk)4-du6*8R?VjT(v1FNbZNdV#G+(?u^Z} z0(ijy^&_XJ^{WkMC|QK0D@ve6wCyav;%cOE$nm?wld%q1vE141{(UM`lIloZaU4=yH8C-m{ct9;2w*CoL6`i9`}eAVTovi;puSJGWii%*I)67HH)mh!?#K2!Qs;nfN%w+l7_%K40>a7fQ{>FrQ?j}+H2qZt_^9$miD z#hX38Z}ZJYWh^!%9$685v&)Z}f#eMIJ^Oa8BNrvOIYuOF4cC&=?FtdfI++5n9OI1V z9{&JJyA&|5pLDHoU84*Dw+aRfeLk`#%6jyV_R2kx&U{{XG{)mS1IbD0_ziC%K48>nV%a1R9a#z*VTSGAok?nsr< zCq%?ig*-2*9+j-;8wZk%VI`9!;fUjt{xy`H*rx~cDBP0-jWaG$%B+|_GLK$6W4&c0 z7H@Gb>-da0{nNhf(l&nT;2)c>Tn-OCGtfySMHX9~u+1mRs&aDNa1K8o!n5PIWtH4Y zvq}`OEW{AU*Y%-PN$zo8YDAIw7Vhk-V_RlivyI0dzl}yx)#dY2Lek1xV8LZ(Jqhnt z4eJjuOK$%FWsh&35abr*0)4sb@9$NiXpOA*F~=fHZ6Pto8Qd6m89nlPRk*3W&X_Ci zFr-g5BtPjUHc*O(YK)BY?|^;(01DQUBv=WHbc|vn%wN3Ty!zHGR{~QUu(YuqjMI#j zEHj>S&1k|5R@;OM##R_u*zS`(&%Q7??T<>%P~~S-D8!@$mgxzM#**-&37oWy4=0nK zeh;N>wZlOKjcYsGxdmF{H*fV$HjqH)2atN?8p5@a<1HYF%%zJGM&cVJZF zP)y4svl7xCK{?OrJx8rYJSt_586qktlW~UG%8(E6t9ATp+@{>x0cj_a8Z{~Bkj%_F z=Qzzc*1ObFY4jSc<||!>NZZI&PblqGZu$OLs)FKpViWI4nA|e5C;&2%&>r1C`qiQ3 zO&WR9Lu_JbgLyXhDqdzibCLijpaFSN zo7P1!!0Zaf*#7`0@vAZeEKM^>9`Z)@$tqjFKGmNb3h6V$1X-DanHUu$gMxAgCvG_Q zt4(b(#dRgLw$V(u+4jUT1MC+g>(BM1*DGvQq^8P}D>Q~>8E~OSI2(UY@+toSYK@v? zefyEu{av##1n@r$<0rR%m0=cn?rq|Td22i@8bU@C;N+iU=sEh+E$roFMYa-w7vC~O z%EWtcKhM&zmotfkX{Kf@w$C7f>JPDQQya^;?Q(yJ?5ZeBQzz)~hxcHF$K z+~a|cd-cy+%#g^T01JnNi*IjXX9G>;e&-nS7f)@}<qgGOT3;|{bZdglpeQ{1dR5D9DPJddml8WVjBR1q6O4ig_u{uLB8o_ikr9?-yLLy- z-#`6&&RV_Al~&MNz^JA`GBLVBz{at^;v{U|Bh6-d<=bYk_ILJlZ0+PSHP;<|I zY2`rVFC(DM5xiNHo!G6M92{}hg#>jaxbIH)=kubvqZ<+;fTI9l4uY17idQI%S38di zL`D8%(;#z-tE2;*fVe#F?O8WDh~#9TUAss4`wUa&mPrHcQjy1xm@!|M)cSf-7c)jq zVUiLK;f_b39=Z3dB;?twVysgQ70Rf_UwLj+fCpip%C%NMmng-Z3Whj1Vt&xqWM&HCvM+i!T00oQeD7h0IAw>>xx(rmNZEn<#bRy$2_;GKKxN@O2%5; zd~B*Qw1Q70`qO2Qs|CSOPcj^OQ`BTDI2q5bd8pX}<(O`ebSyu}s^*kX({>qd#ngeH zHFs^9#z7~qr{z}$)&TI>?^MK1=N8W8jX!{OZvNiYZ1J3YxLyzN{!~E}F(Hi(LUIpW zQ)EcnYqT-5pl>L!1-u$adul0fax^r&;Sh&-aX-MDg3Z2f)d@Zko+ zPSSTK2JXJ};S)JMNahY(%tjmVe4yQZz0Wz22X_s-@xLu%pym9M~ z_!0H2#IV~Xz;z}z$CfejslfIX%~nx~v}I$Ox3g%Wo<+GPc$9fA_#v2kbmWuM6|rd_ z?$Rk@DJrODJYkPHr%P-T_kmHNi13J*48yfRpJ$TdIgHaVdCEL-+B-)Z4^y|C9D}zw z!St?gi4jt1vvS_*8KE}rL4P!aSyOK2$s+^40MFr?bHqH;pWNggB0}eRXZ-P9BylWC<~)gHjPgNYoYu7WGmKL>{YK79*(Hd?WAc}FSa87q z0H4;lNo=ldE+&sM#}tK@Q4FPX^dp~MYu6|8%vW%x@LvmZ}hd zIURZZYd%{Q%$dRJHjI3hWJQlGV`$L2l?U#F&=5#G`h5*!-zvah4IRXT%q3ND2nRUz z7$E1G?JmW;Y$VJr+8-y&mQvnZdZ-w{CoTN*T!qw;pSDMA8y3hKCB2`_k%{9u{^=l} zVaICDO{6uWIqBe$l(e%v2h3&t-_5yuXScWGT6%S`SizFrN~4hkkCIh!+XsyG=CSTB z9$4l1gh+}vpe2Wy>7Re;OJl7Q94{~<_n63ElmKzlp{$oXXI(o==JU$Vk%=+pDxWZt zM&qBYRfx2*y{*N)$JrxQ#L!LU^*oYBNc6z==9t>ng!ihDO7{`tbgJvNO{AP3=39Ca&;oR~|^buGr`Q!{+o&PhC+`+L`0r#w)=UiMRsp_Ig% zm3;xuI(q$Ty`qtfmnu1ny;^Df_PSZ+oFfPl0#-EzxFt?^&MGsriiIzvS7;B2#lsijEsN*A#wA!{^@|YqCTKXpg>e(>cX-+I{_{mX{61!icRt%DZEZ z92{Wn;Nu;-{#D57vx_BY?<7yF=u75KCN00j>5w7P$RnhUblu<949 z9hCDXV={4^j`$^b!8jy$=k-&>x^2v}V&+S`&G2rN+dj!QDZxv1AseM^BeyF1Z(h~tzoKbUO0OunKgJ}^K}vqLnviD^dRTcITig-_+r}a z?UH$J*u_7W=h{ICSiu|u4?DO#vG?oNzBeqytiv|MO4qc%s~>-k!N&=g(p=wXZ|h^M z0j4w04XxbfG#*pOA3o#IWMaN3{jD_1X7DzCeA+87mH{2s^p*V(seB6+V8 zx<;rL9&w*6k(UG1cfjvo zXNTqIM}?OADmkS&y^~*={P@O@7QSfGR4;VTa*_bvKq0>)C~i(V^}smIddGk?yGifT z^{?YpR}i<^_cYBT0#!=3GPwW}nFEga&zAU#8Lf5gM@-csH;-wl%eGkw-6H~6AE-S( zgVL|~UhdW(w#FouTh}Y)ByMt%{KVrYjO1j2&IhG=Ijs+?)SPdr{nwY~Uf%-=QlDeB^bnk$eq*9J+nAtIcptzF7HjnHg1^0ho?eNh6cM$gf|~V>UYH+I0Cm*MIo` z01qK$je$QZmN~%s4@%+7s?Iai{KJlNX<{(7B;LL3eN*vo!}s1f_;0Leuokv~?8uVk zmujf{$0UwM1`a*@*YJb;b$lRyg#Q2-d_!u@Jjtr-7gNh|BZ(v3k^ZY6!;_5U^y`i* z`?ZteBzIZ^=%NKMPjBVVCg98upyM2$Lto1O0Q?oh;jxd!dS8iJ+6dCh)=PJu6?Xee zJcYwal2kAp3;;3ea%=Q#j~P{AXNHyeWv!QU`13WTR-R!QN|o&G=zal3eu;1-D}t-G zG92Mg;a_)t%|Es$iT(^*!(jI^Nn>qxzE!+ZU@^}Hxf$aF=mmTqsajcmuICP5byq5L zka_4aSn%DlTe~F9B!%#*%lDh>>t8F2rArX`YDZ>zw5!*r3ntb3T>hP;{{VuZX|ecz z(^HP(;%TF|WNB?C5y>pLB&gg-2Ly})cs)-hzEJqX{{RIjyYYpTx@L=Q{h6tGersH6 zL+ueP$_@t5HnvIYkZ?M3Yw=M$OQ>7v(%VONs<#m@n{LozChZzLmn6;ssTG z0*=Z(2fuTg@w?|DX-vmr$a!LZX2nDHh`~rgncgO8GWp83N$dW4RiSYVxp}RP#sCW+ zmRW-yGsmZ2=ULRmRI4W5=d(^Qg(VoR5uX*Gn!@Jj;ti+ENPbpj?esM0V|i4kmQV>x zM(8%S4Qa=0f;n2|LRJ-Ri;cyXtyhNRh6N+UlksRA6)L=*M{4Dr*qk>h$!NneC|M_+ z3mFRrVeEdja$W(EqrrP|xtFeg#8n8QSk7e=nK@+{Awy>v{{ZV%*-(fR6Yic#n|xg5 zRChhFeX3yfIcAL1ExklCEQm>IH+2Kjoc{pn5lGNDR%?t~hER5#@+r|l1d^7LIU(BQ z$0{B$N2lvr@LFl{Tf}YFX{3pp?Gnzxx4up`s2?vKK_}~5B-w;lnVEWIK@oJ0S7l-r z7TQKQ#wl$tcSgokgv7rx#Hu{a-7;vq4*O7O30@?NQxvFRzjfwKQ9#N zM3cs{OzOcPKjosxS0jL|ed?<~k+VfJyLnh$fQDbvwoz6ll6JWn zM-j#y)uN3GGW2O1+NQHXEblj%@x}(-tq?`%S{mkQm&wj$_^24@%V2&_(2{ zC`sf4Z<)h0a&l^APfM+i%2DPvqP2VJyuOVZ;B7;>*qi~!=goWn0K*^I)5gCL@9ga~ z{{Ro_Gnpkwy#D|od3Yz2_zq4#t$l&}8ve((e-&)B{{S2K!%uY3}@SA+88aNwEcCHQy zUf4YWugkyNgZ5d{d`;myop(&qA^TsPvpQMbrroKLxs^#Oan2hDq2P7)@~HDaXIf58 z?Ee7ZSmDKDV?v{qpC{sfC=!37$vm0Y)c0W2)7BU|i7O~{mS zl*+oSgynOPYN}mG(njkimcYod?^3G1^=9tqEXn(S_K4%RV>+qY+q2fKKz#UAh_(XXyT>h${=G>IBIP4!Vo+{E z@80`H(bw^-X$z6%5X%gXL`4TX`M?$DRE$y64u`n>5bzQ4*NQZoSmbS%v##jM7A$ge zzothWKDg(a{+d1tcuD*_;f*UtI&wt@oo1hBFhr1}2VA#KaytSs&#AA+AJ`}1Wwq_} z-YM2+dmC7;0>yD6Zj3P>sOktG{=eQY25Q!}_E%P~6I@$bD#EhO8U5kf3bJR@Bay~I z^sWplty3K3FNJJ-H0MTClw%)wo$lV(Ow=H4&pB<@vBsz7Blu2xjDh&}uP4{FOTm8D z7cfSUt*WTFhE`@{jl(KH0|etB^N#iD`pw)aaCH_~%uzzw2LP5Msr^48UK@FRHT~Vi z#nx0|f~&6H26^N2{{Z#ZsfcOxKUm;QzVr5tT+Y3KYB8n3x{NZ)%OWC(@PKU$a0di; z9FxiQtqnU(5blP~<}1IlK&uas;ow-;AgDgajDLkthVO2o>k`L)^IF@-ACYVlGOL{M zpbgzJah5!iNj28^alXrRWVf%IHpnyjEfx|9$7bNE$00V$P_04_!-wQO$M-Odh6HhIyf;WhQRda$E z=Zxc_?d)swXW)O0b?*nqVz$0~Idzie*X*oekxoJRxEULO1JIvJ{T}ew#7XrV1h;rf zO)M(W%exFz^#ouX_O4ngRO6}q=f;?t)G@M>d-ORQof_juzK%b$MmEQt?HH0c*dE#7 z^V1d4TWVKIOl|WSmk{qEcBuC~>G%4?dc^k-#_+7LC~b`>4$Mvf1E~iGpKp4O1$knQ z3y(9+X4)fLK_qMQ4w4a-AoRyxeJg*6_?cJw#BU|3wjqw;AzPm;T`LCP8gLKOJod?~ ziR@=DG_pFXGAl(4a+YOoCM`6- zYL-aw8_5wIDOEgvHD>!xF-qy=O3V=&E2*RM*^?cxaf6)k_;u$26tP$*nmF185$?8& z%a3n6Kv9#BpaMrz&w3iUcd=sOU+j16w&gD_9!yU=@&3uj=5wD;1#x$?Tw6;CQzR}Uobv%ak6#I#m=3;l7 zc_&a}{_tbRx&Hw5)k#wRGN_lAHrB;=-2IT147_Dr5%*4ZpRW{L#5KVsRs;K zzqk1n!OK?ri{aYAd*%knVL7;cQ9O#ewjF}f81}G30r$Iiy@Jih4Th}XY0^$ z$72q%f|Qr_P2ZKk={FG2wvWDM_qdC2*2GIB@Ow6xhIlFHWdH%Y9Zbz7^aV#ruz zHzSN^wROT$XDsc^bRKIBLfYrdLT*C|q7r#(RYpnlEJx;j%}aYJ-mpgujF(XEl4Qms zQTJCJIqUxb>aJGyNe%QlkL<}jJD^zDvcfZtdXe-z*2bA}c+n&-L)%<2R|exCx`MeO zd#*|6k)LuZ6=x@7NYhD?&1-9AAcx9=k$xNdNL4P3j_e26BT`OP)Ld6y6)e)3_E z2n+@T5u6i><3^dO+g=Fw2-S9o%BX1CMQ@u8$YIWS{Q<`s6T9J)5XGoT}9!Y^``$Tb>3aBc|Teog|VAYF<^HvC~mH_sF ziMeFl(ec15k-iBEwt8BM*|zP z9FfWaGescI?2vF(xZsS9ydF+-n(ioWV;)-0!bOlHpprFjLZo1iP;;JWi!U|RrK$kp z1z7KA0ac3=)b_`GaazUBDH_Icx+K%2w`+OU;^J$V#kz#^RdX>$Ucdkke@;G?1fuWz zOI4b}+QQP-;HkK_Kolz|%9Ra}8z00zW7C|P#+uUWPm)HT%KJs6Z-}h#gv&Q03Z;Hf z-A+lz@;xS!TInVJ($ntj?qpC>(@`q2XQ*Z?!3;1)I}uw(ZLwC2oLfgElil0irPrK9 zspbjU!2w|){E9mRlb*T!Yi`=+)@dberU%#7yS*+8d{28WWRhxcp;<`Ali@^kPFPG+SF~Ug{uw|h2;Bl{!TubuN1kz6st1nrP=Nyk7d-}I|EX40(PEuwg& z!%7McWIl(f+m1VPTxExb?Ar9BMQs$4!{}J7xIE)0k%P(UUbCiY@c9v2!3tZ0 zZ64M{D6B|4;E-}U9z7{S4aw>i=j{?ai^X0YxQ=siV;fva9kVmVg;OSZ#(3w9SCQ(L z_fRq!wEN$-K{S74iYZlc>~Vspmcr+bIUwhZSJ)RZM+{dHY>lrW#BDsWZX0@nKg1ti zde@kEgG;x)xx{Re+|440;t_3TJm;MEI2}9n;}qtUNvA6$jzhuk_Eo#`t+eqhuq#J* z3?@kAn2cscC+210PB0GMJ!{bHEqt9p)=7MyHq$$l72M1*)6nzBy?N{!gc>}8#v6HB zcz#gt^Fthai3+MYQVC*kdE7ngvC}+LW2kw$U)o2OvWD`%vWm#Bv~E9XI1HzZAkGMG z^y4oxx`UEuqQz|{pKf9EHbpsBX%EV>5Px33tz&BPYKtYul^2qbeAfV;e6xa>UciH# zp2zX3Cf4TT&5{Y4NUmWDl1$9V3i3EO0Q%zuS8C5 zsAXmt86D={Hw1PT5LLdL**iQBy5Re8$#nb z9)~#T1dmw<<)=a21FdJP(+4IIfFNv$WHuWQu3FNv>8$d!+K@+{=X} z0X!A;_N$6;S{qaMY)^Zv!)ZOe%QTBDptSN3cQa)2bKLP=T-v>@#kIB6k8v|Is#;25 zGB5|H3JKfDJaJsdi1Y@(@><>|k~1Igl|E9q&N0`hBcFQn%UN}JwL6PK+J>0}S_QLT zG_!e`$IXHPQagTiaj4Yw2|_*3dDA>iV>+a5Ig)3&l0UPqOMIjNPZ&FnK*7%kJ+tAy zG}SKe_1n8Nl0WRpZW>EOhUiE@Qb624g@MiiB;yCYcRF5-nq9Fh+?^y}KbmGI8H7&@mWO z?m?;HvKG^&tjTn4rGc7av3~4eoDAoO_Z>m@sD&OyYaEp$CT?q9B}-j}e8=-H6}-1# z$$&vjCO9Fv&$#J~of|8eHCa~aVQ9-wi5!u%t^vZ1ymcqsSCHIEb9Henr4}zP>9ZbL zfQ%jh%MuT{&3dYY`%q*^N(?wvNy{NGerZqSjOdFg~cwN1*q9hsw%xB&qOvz6Y1CWtjme#g6ejW z5*3GqK4D$T069G|`TNuCFKt9HVXmXOifJAsXwKH%##n>M$3S@J)KbhR#MZANXeF0( zL%fyT6o7Hik&}bhpL)?)ChpFP3D)(knpqVdQbabJ$L|~r?Ni*~X9wTXtXV*-B%(oT zh9qWtiEfolDs%Glfwhk$p6kbY=Io*=6tO&#Gc0T5$npildgC1NyQV9oh}cOBe`xJw zXN;^~Vwntqg9h@>OE1cLbU5db3-?N;7@Ckb?xMEYmL+`IA|capI01OcQJm!9dvV42 znA_YnubN%sK(ZuK4a*rk5scsyoDt}1wY-+CHPMac5KjA{^KFcB1Dn_5WGB9S09-x1+ah!V!jvJPW z-p>l9W{|XmDBL-#MoDg@+Y-Dg9}L8R52*YH^QX5{oyO>%*$idcW)|&o8DwW-3k)8Z z$>e%}N|rs2meE^TNefLP;@wa-BpvcPgN{4&&0UV$&0}w{fM5(K9V9t91HMN}fugwH zRU{Cr7G(@Fv8dw%+rAD>JCOxq)DuOMZ!*MN%nU*^Jezw0y#kiV&pipP87K2p+Z0IF zIfDd3IQFRRqXH#h!KG93NEB|*PJhCzD-W3wR#v%;?jcon_2izu*y~M2wrR+jn&Wo) zBY_UZI~*<^H9dL$>En-4P8*zWVyhg7VRy?FBydQpd#GrCp;@D?e!V`MN)N% z-G|u_PM{s-LjtSFKZjbjVPCT_iW^wNINZr``^I6%-8lUIl=&I$#1nal*9@$_UPj=A zW1nIPterI$V^ye>5kdnXo58Rt>C0WomMxH7#IY()gp(lwiBE6Wny(v?5eg&u z9A|-(pXv0dpqNLqWRDDz<}iH0^EWwOdgXsi(@xl4iHv9YG(=R&fK0m_9r7J`O})& z5r)~rv`nKb&RdL+e1A%-y5c`FFD)SRWclEGg_%)@LQ3%8g-lM_t^zq_U;?(lHw^X1 zO0_1z@{E;Q=H$8-c9EG>HyBaSpZ>K+aUa<;nFv6fL?bT7W098s0B1NJ!zY@(DEk&5 zLmSG$e7l5VO7-LX{{UK}dfS2`kueH9=^4mkJD;em`H(?HA~~a&M-wsu6K4_;!!Y#q z$G5FqNnp2zD_NwTSDij+q62EoGC@6ZHu1(WpFvfh%QncMakw)wpO_v;>&N6N6{bmY zC1{yoCKZdLWZ;HA;Nu*3^{DoK_Jm7ASiu(9XH^1e2osOu`9=dDzyZgn<5U_g(mFN3 zMpfcQ9Dbgj-n5ZPboRuwMHLy80^m06@IW0w9{h1t?hDO1xMp8EUB*coLRqB#q>S@d z7^t!w(?eQalCq@RnXSUetg1?%Y>xi`=edS6dKua+{i8uo_U87CUJV!D~ zg8u+7E5%xjj50bYHyd$s#et6*9RbHZ@-x8qrneWgW12)u8Dg0ZOxwYA;A5wMN=L`q z9e&R7A%-`_$I42u;DL@Z4u3CNVx)%YBU9!_Bx4}`)dQ(Np8}iZT)e@p3~y@~Z#&LL z++)GU+#CW94>=uusJ)p^ZH3D}n4|43wyf%9ws^;vAYAQYIl~WMbL&h?$X4c9Y+6|6 zo(3obftLAYhFwMGobR@>?9@t;n(Y2{e0C6O$xT=PEj9IPK|E&vGx!R&w%2%C908 zQ=cf6ZKsY1?8aryhyPmeK*2FheF9ag4Cm+bN@#3L#d zW0|r;E;3pB1Dp&mYOC3aTx{E9674M-ysMM6`CyDO0FlpbNA#x^iN}~iZg&3wSFn%= zwsVY7%I)UJS)-0LU5hf6T;o3}zy(fo`SY4|@#kH0v3>}7f2d6!|bgd&K znNe*>fE9eha{EIwNj&k!8bbKMCy|`vx%H-xBH@%HJ4CZ8mYF=gr`H^kIO;P}qKKeC ziM0}7WQ-`}`~JVJMJQmRNaIjL9jI~!&)43zI;l2CaAjD`gZGi{WoB$P2Rw7yqKXuR zJeKgh?KBESy5O;3NdN*sRwut5xu-mV_}m0&fUq18x$1qmqyVd#GV(cQ3`oey=k%_3 zbv9_~^7SO11LRLM(vqyLCPM?|fO?WTVE+J0xF?SC58sqC%?h&3835#U?an~!*P+cz z6`Z{9A0x-OIm+YGuh{6f!j=a?>jwq;CUCd!`Bq;2XMK7G| z<*Z?zNlXn-F364y# zM#_vFGB4sfpL*{sZDTM%%1L(Q#>uqp{Bi5vx#cCy^e$M6Z=suQpj$%`iI1A@jl8RJ z7bJ2)%AEG&jC)qRx?~E`ZbBnP%S3)rk-+^cbv%~)IFzEiQadk^g3~Y`cY}lY^uhG4 zRxrG>m0pqj%0_XTwFfiLs-5n0@Y$?U7TRQYQ?vv3SN{OlQA}h%DqTc@)CeJ&31(n< zRmUE^eg2iV4&urrTrn)6RZaruij9KDDOU(TbZ`RX2G1V7M?Z~e8a94MGnJV_-fubs z<)Sl4rCFK4RUq?{ap{V@vB_`(>_8)lR0zh@Cw_J=z9y#Zn?jT~V z>Dl{K(8RKc)<)ePN8^Lj+m1gfnL#NQqs+$11oDSCcySiMdQqh zatXr$&u*ahqF9jLvxz1Q>$NZ##uOfT&H?H5$FQr>f+LMVC#K=k1N@rC`kfJiNfqaS zszf7soJKbS*epowaey*?Y9`w{BRd7dfYIHh%gsczM9jLhI$v1Kac0x(B7 z>Nz|f`0gqV%INck>KY1qvHhn&xrmn<0Cdq`5A&EAu zzGH1b6tUmW@;xzFx`gfLEHS^Bk1yWw51LhTL~M=Rw@A{f`jOLeicdW zC4k9x<|!i$#>6VSN$3gBAy0qnQtr`|Ib60g427bSIO2_*$UbZp+&UgdJbE9~H7rnv z@}>@VGBj}lFu_k%9>*sjdY@Xc4YX!?B@^Gs7G_n7cy^>*0#-BJeA&;bHDt$cEy~9m zF2S5Xm;o|!Km+s6DjY6%ML_3oG|1=KwR7c0By$-&H+B3E6E5Zx%JI395*a1=SYdF)u5vJgAujC1LasO?)&6lGwgjFCUec9m_};NzT(agoMqY3xJ9;xY2e zDFF+e;ZN}%1~PMj?Nz!eoLXll_7IuA&Jd|)D!WGQ$Mx+{-A3+SIpU6S<*&?$6r3Cm z0LLRaHP+l|+p@vDsL%!8RDfF?;P?Lk6H$GWaczU@yqwDs|uk*nBTK@-d6vcu*K zsA0i7bB;YL=ttApWOadKG0t|nn76X8U)}dpp5vaQy<+MXE+UHPqbkVl<`)=kz;mDe zy?#%`IbCQuN-eKLz{KOevxs#hwSK4O2gDx=N#Si`&F9InakfQ9AwuUIjPc)r*w;Vf zj|2EqQPQB*^t(wk`K~1idu?v4Aqq}Z46!Ew^&>rwahm&Y;#Y#=@kXBVLkls9NsWvI zGZD$);|I6pUQgjqhZAa6=F5vLtkwCT=0tccGfXxZE(gSj-B(?zdp6u=DgO$)K=lG)goE6 z`vR+$T!YU{`;pfq=Qa2F9%CHN4pEkdQBI3#o{ga``^j^84ehneb52-^trhOP!a*m^ z#_gvAO3*2e3tZO`Rp=fsjw>wuSjFFYj0qa@1*Mefb zn$hj7ptjRuc9IApwg^x+A#&d~02l#}9P}jCSAnkO)jUH4l2356T|@zu?)>2jHgZ7& zDhp@j9P(@F-8)EaR!QMzM2#)C#?2FLXB=Tj&6F{G;{sw#v~8Av>me@;KGc;=o&ARn+dJjV*1o{IrtE%Xw-WjmHIe$5YRG`Q|?c&#YhROR8zI z8RIJNrCr7hiEtY#3i2{A4?q2S^=Qx9%SWO4o^yu8dw(NOLe{n45H;?o>gEuER(ZDu zSaZX$$IH+3&sy)iJFVXMV6$tsmv4BOXbqN^B-Z8}^3K2zt)7Z=yOY@0f8g%|Tv*Ij z`pWA_+T2;{1T(6hbAU0mvRDs8Ub2DHSvo4Xu5T+#FMm! z@_ZUZ+&_cG+z+j%W!s}nkc4U zK3EE}M!f(dJ@_Audi9;%+RJJ#^$X^)vx-l%Six>41=~AA41yPTQZs-_!Nqy+g+3hG zI@rx*Z{o4J!(CjwfQFcijD8$o=cncA^XQG?+tj|3`%6%^l{U$BHP4vEx{DH|+)OMEJlt+*lvBDc3f#e=e2dEu0Un2NZL6gH8{hapkvT2t0 z6D$i5`DC|d%5l!p2d5bAR|tE~?EN1t$l*?+KDGYbUFytdM#3#ddPl^h@8Y>>;hZzCL&*8tU>XH34nv>Khf zCGGsTSQsWtN)Aea--F2NGCgZT*H6;zH2Ymb;#jTV`#Q7Px}P#O11xilZT9Vhn)9(L z525;Y4+NDM-CY=e5&TW1+59!ThUyvQyZbvcx0p8Vkc=o8$i{g-{B-B$UxI!+9vJ&* zko~6OYo?CHC2uY@gy#q`kfWTF&r@FO@eb!o*R)xzv@Jr)Pu~c{v&3eNWFRpNqXg~2 z$Q?PaoUHT()9*idWZ=V}w$Ck$meH()@MHOo;06e6^~gOr@5`qcr_9LutSMGjkKTQY zs$N`c+6=Rc!xfuBBRtlTi5Vnd10Z4sKsg-nFi7iP3~SaGRyw|-P0HR{TSm<-#8#w7 zA#OsD-N50Gwnt%J)2e)E()520-1u7B*5Z4Mu)@;$PUVfdZefqmAI7%@h4eoQ?zKye zHuOt$#z|YwRY?H{V-@}`IS2ir^gg3%t4_z%;%7?{gp5(g0>gl# zot2)_d6}#+%9lK5W9!JUVwJ4 zQ^6k&bPo>Arg(!;n*RW0%w|2X>as@}W+9tt=jKs@F^=3;zs6vY>KZMkpK~SBN)%i` z&c-$;+t_k3>+ex%o)XiwT_H7nPX6^~v5$4NsF|_29uz4cD`%-Z@y|;1Ij2o?GfcxF zg%~Q5-_ZBXQ(C!)!&jEjgpDRg+jBBzMu_xdgPf7i2fw|1K^~c{rlE7GpqBGXnWaMw zoC-@9CwCn|^~W6J*1cE8{yewP{4IBDCGEo9J;K8R#DYc%x08kHI*vb|UK`=x#l06# zhWZUk(7nCfD&Ac78>C=)0e1|>*<6xw!62S-Q&NM(CoZSu{6#hGIb6Nv(643TyIof0 zZ?qw82B`xThSoIO<=f*dS;^xqfD~sqJuoxwejV`Mh?){x_@Y~=FXd9;TH1##GMt1# zpO_UKo(Sh1GhDj(i^A7-U)mlY(mv0!?Os6z(xa&W{GkBDDH+eE(SkEpw112`g_M#( zcV!>;d~%iAEYW5vct1HCuvfQ1&#f#z26Z6x)cDA`NxfN+E#im7lc$Ct%RpoDtmIb7 zW7Urxk0DQ{4r|~19pI}=n4NX?)D_u@S9`-5ZO7&(uNcqE$8JY8=5{*8yt=vZ2AKz& z1OTv7CT}if(gSUZW@EU5%#3geAd~s#v~;fq>3$uW=EqWs zDL&PYv$RD(WfrUU6GO`?# zxR7!&(9^WC|3JmcGs@%cx_`j3ruEAQ+b2GW1BO3o#@iXx-|&<4-b z{N}fHFWM?Jj%^8H*bSc9S!P(&qHWKaT}@6^T_qVVJ8Q*kDSEi z6>H05wDGTnd_{Sz?s%5lPME2IWF#v3@-w(&kUD3*b{ZFfWH#_H)ROb%RW5P601=Kc zitsBR9C+WvhHFc~E$z*vvdO9)KG3Si8@APB$tp8}o|*R|yA3DA`o)`BEcOD=?CQU5 zM0`my?l_UoNCbcs5yk-HInL3*&r=F~AMGd2$*Vp38x31WX%MTKA;;MWVp>2yg+bu| z04_eY$Y1F<}F5Y zmd;Jhj2l^IVaHR>;m89Za&ywIl`csoW8cfTc8xZ<(d}Aaj3v2(B~P<$GJKKW0?hH? z?P18;!2H7`j1Gr2&FdEsCG0mEmF%Lc@H6M)z~K|E%;G}d%^WxBe!hHY2umkQB{8)|vd z9AxlIZ1g+=0qtIY;v2_?)By z*-%FVJPtS<_pe>kEbp|7n_GQFts%16BySv6`=&-1%QV2?t7HH(#tE;RwJ(S^J`aw0 zVw_w{Z8ystszQ^E$CKC7f$dx;h(0`ckHoN~wzHdSORptabmoyJVEknKps5^;`)Ag@ znsjPbg5^rb*x)c#`I3rBdEEO;UihP=#b+j&s@~a004p3xWwG4koSgMF z=h{z=ycu>cfN2@6?f{ugEUP1SBafJ1fsv8H74jY8YucQSv);*hJ=?2EBH^S}>)-p> z!6TaLd^O>V=n~rYS*|VonVDu1I|VS4yK44alh6MEUb*oY3_U2m=jgd+R}W;lq`xEU zDfN#9N^LIfhNo?-X;DcHt-Y<l zgp3t;A5oUT*{)BS~}W7^4iX=9j51%-eqqwdBztx z&T>imeluv=^TTGg48~ZWb}iVI0kUz7`e(PTd1aT2u3)^oH?hq%tnuI%0ai6V&Tw(Z z*C*1w2HNLL)or1SNVW)IUov-)t0%rkBD{*2W{qr~WpsCtU0*C0V^36{&GP)q zXK}Z3pP|7SJ-?kxYj~E*e$itG+NP5c&dy6lPDXg+^YpAuF2?6ixtj4V+Va@kGd$(S z`8dIL?nxt&SFdhu?`25`E=b=J5CW+FwaoDM^gf#jg{0RiJzv85)cO_BxsBnOj4He5 zh)4vS@4_j2S-hQGtag1C!MA zs4ce5Gi^wOa0d~T0evt%eR;2o{2}6fN5hxJ<$I$Hupcocl*r!xxa9CVabHe&L&b3T zjUq1uk0^FjRsgY6*khi!{VRhLfvHJ3Cv<-q@t*-2t_s=KTVyaxu+jmM|Y)E%W<(2_+$o2QB_mzmvG>*41ov~Vp2Mv+OuK*uU(yKEr z{fR3TD!Z|e2|cmwYoO)0>xsO^WmYBQwvT+%9BwR52_H;!+R4SozanzH?PPHJFS(;>rY9Wmj7aWXoao4Y+h=LC*G80(&ujYj#6X|R|;&2i<;=8&pH zY6lWz^yj`QjLQt7-PuF!ELE~R!_#V>fQ;uSi~~<%k8KR5)W;mo%qKCG+}s>=?VOSH zsOMK`&D6H!#Sv5h0?e(GgU2Khj&V?HbX7Mu5GnI#fLlhJW`w|{m9y7>Ia9#n-?dJ$ zh$caDtt>)N%^Xt|J9C_8pVp~eEACX6$XFZ!G=?%Zu5*)<#tsJ+ZXjj2k~Kphj4);1 z6`1zNZhGdeE4F6mW-Mv@spGaFLMPqj%Eg}~lh^V6J*lq>Pb5%H3&j%<(_AB!`Ns-2 z_s6f&t4(ZTxR%ZUiRDVFV~vX_$3Ul{1JqUPtMKw#?kZl|P^ij*V|)$2H)4OEUbU2> zliuewNJ^tbmh!^7dl@4?ZMV36lku^WJOZQ~oOQ{;&rY=2r3N`6cZEwT$dN*uRgO>Y z&~_uK&!<{LYSF)ZiKNPOabUmr9S0lHU%!Cg(tbU7!b-Cqipl@a7XBB zIb@997F@+^dE>QNW{^uP^J6KwmNZeE05gNfe!2WA<)gfkFP8vq%mM&QGiN=$@<$$( zQOPi*^QmZ~j0Ot3cPRJdf0I+ecE4sTBz{zma2_|>#2n<4)Di7e;NphpE0$-8B@m*< z_UQzw*AYgaGdl(VDB~b;mgp+9ma*HmZSamIG6)?qk~eIOaz{*5BhQjiaH?PI@bNKH z%#q||XRs}|KKQ3cnbt>kSv-=`C}!GBhxvi|3P~MMxJ0cl+GlI1qGKPJ@k)nuho;rX z0Qcw6)YC+*584!}?^xRASpH@$j1AwGIqV0gHC7iz4I-(zibLi!ZMr1lx@GX1(h44GLlO4>~q2Aijest z8B#6JJg%y%86W_7Aa|+vn%K@xHY{7kvI%b5K^z1~9!X^+#=LTP#?zCN?0BTPOIUWK zS^Gf<%*{4qjGXOaobFOH{{Yvi<1))`mWc7kZn2hkkciiC_U>>xfBNW;G-N~)Y+?g4w5HbOqK(-_`pBjhU_S2N4&Zv9LMe}K%-h#% z`6#j+pI$INooTR7C`)v?hBpQNX#UdJjk+DU190kj6{BpcF`5*YeY!~52k&!{`VrIG zwskCrD5ElVl3ST05Hq;LBE}0T8Rr8@;8wAN~&_W&Qx>n-n1lvCzK*c zgULX#58`4w4|0L!v7)|CIqpB0^{b54&e%;!A*ag<%Q8xCb}x_wr9^7kIbqa-GlA-J z+L;uSh8aWV1U_Wu-~wAdhp`>wg_Mv6*T>!W z9r^XD_V|Re#NA6PBMgz;o_ieB>n(wlTiR~2`&aJ_cb8^XX}K-4fwU8n7qIVGPB)VX z(-ueaPA3QbA$J{^VZbW61As<FIPAFWJMMcE>xa7gk1PWWVxY6O5OXX(iu zPBG8_09vlk_6NFv#LCd4N9V^Q2HPU=-0%p<EFFQ zt*scbCCpQw-bW1LIT;5~3E&gcKK}Jhq`b^!KX_OS=|9>Xo6Fz+g%olXW?*taJu`!! z#;i{?mk)J4!aVmE6Yic#7|A0@N#v27=ehQ%0&jMX-8{0sXPG_a(#Ic`22?0Nb%!}@ z^N>4Kiwu!wSk^05D5%eB+({=nez+uz46Zs>P4gmL+Y%Q0M7~tsWHxruvq?6m}pjM>L^XEQN*Bvw{z4utT->74egdD3a-5l3)R zRGb**w7@yfL7vB_@;&QXa;Bc9574UU?<-2mQ-0;QmPpD?8v37R9OK*GtR=O~#`&dq zrH(D4$Ekk2=aMyjg;Zineqr?Tg0|vZOcYvESry*IZ_9FdXIXqZjsFQ2_qP@F5@9TGm?Af)}M6{ zWSTTAj&t{1t~2!HV?C+v)6S=Q#BKbT)toY^Sr>uwj`$hRU&Q9Ry``<8wK+XB9W*xa z8DMQf=g3tJarPTo7BwyN1Xetp0s(Q*=M@~+@9`%cb zmfwl7H1b=>rAw8WVOE)W3aUrm`cx_;*dAAu$0KfnCnL*M;2dCQ)bs07Z6IY96CJ{Y z^6(V-d}o{!R&P=VgvA0#WR5c7M?$0P#YZNF5an}v72pQVuD42(;43PI8Eo_zr#QKl z-rZa8s3l#1WdwuQlgB&{NGkVPSm1%}q-jbtyM#9}X@cfCBwlv1 zu>kGJ4W2pAL(8SL-4(EzE@RBzWxSCn3o8ta9&&o)@fD)c`EB;Cv3Y)2z)UkJ&pdWH z_5T3%+M##3jo&)6D*d??C19j9S1P97AI|G6T(9;@gNvFjG-JjC5JL=h9sZO;8yYFAXf2(@ zh?1CK5(6;Y?%`B+ugj0U%>fSxFG`QU-C!Pr$;2u9J zKE-V;*E1F`DnP1J%{V6+~=pK zUZSkBEQTaGK^pR^cqHUw^{TMNb8dFP?5Pyb8J(^6uwnsa41V(9uTB9czG=T|xPgL5 zE%O=M=SLH6JmhZ4Aoc1oQD$?iT)!fue<#{T!U>mYP_eE#-JeWit2wtzgA#?>`&i1j z2Oa%*H0iIBC}5Q$23bo9T;~kFpPgs2%OkD0oEwM6E&`qx8OKh9b;WcjMJPkIk+pHua1T7>kyoPv zNuYSxtHz>0vZ#NTCvx-02R|vUmG2<3zTt4z;pg&&wUlVXWLB$y6m}g>J9C%WMpI3NQO!`s-B$GJDFu4 zCy=sRvt>am<$>SR{{XM;Sv|{JZdh>A$dGO+8?Nc2SL7}^8RLWR>-bgZEv53r(3rf7 zS5;N>Hn0R8pe}OC068Ooaomc>x0*zp%78hUj`iF&sq7SWBd;d4CzAFU$ZHwm^Um00 zlPa=s3EEFk0UV6>?^5KEahtxZk?$S_FwUSkc4$SoW-<=h?5D3^tt3WR-bs=y15 z&o>BJa_(6{Zo|-ZKaC^2q7?z~*xIq4yMXOeCCfb#$5xiQ6s{IeHE>G2Wx3msp!4}= zrbba5F9U~pjwNLn8~gtNpL$7VjTMwfBS`AIw<+Do{W+!x5gI+gWSvUo*M(8(iA@bph<)ATKzm|o($1Aondi3CdpJR@+=)^v3(17tfFlFUDBKBtVIqc8-@ZZmbg1TQA}6+v zHMx7EDmgacwkRvR4U8!#9S9_6wrRI9L#HG$vr2NFW+PC_$GFd8Gr;#gl{^;8t2EwO zB550JilhysX9L$6{cEZ-RtR0puI^!sM3Ag-ExQ3Dau*m1G3k%<=?%W!(adB}VpF;` z0FuKz^{o{+k)kNxTf%on#Cd0EKD=k2sjRD;IGNcDUuBLPaK3CrgCjA|9eZ)c2Tu8- zPng{+8W$c^_VAaF%Z_GN!2b7q(L5;&osml{iEgaGqNvYcIrPEF$680Uf_Po_Pdwrf zw*FS2_UpSj+{=O(?Z^XyPC4SBGRJ8gP4klFnb))b>}(BrZf@G zs;MYtS8eO&W7M8~eZLO%YD;!#Y?ddtjE5ib@~mS6zIOA+UMd)%ouZrVPY2H?Vpw7F z&hBx>Nj*B&bs|!#;z=NJE_eBW<7$j#^y^NKCSz=<*;XvMQJu}(ILRDm2dCm{CRSr@ zusRSAp3L7V1E(F2*Vo#nh)oPIEH;JI$tLTmCOh{r+;h7UkV~wF^rXv7Uc3cvWvPx0Y2Su>EscI#F`DwW(QXJrUL@Baz$9R9Ml$1Ssd3AdFnlDrV1$>mFF9f&kGr33bI_zzc$0mG4$sgnwIBts)PHCGZcwrGHnFsXxvH1 zUJYE9IJYX=w5Ca8U9wFk=G}lvCyb2ekEKU?RRY|J?`Jm37U5mdgOmJOAP{m6264|d zgxW~vjFOVnfXJvOAtahZ8CarL+vUgzJC6r)mB`~5J@7G9F8<7~BFI8-i+9SoJG+e4 zt7)RMyYouwI;mJ>@~2-eHdtGXxZnVI1P@V5DnoZUk%U26nC@2E$~^}?>uPBuu`X_; zQCTEz6h$N!#0Q28iCD;`{%(v*ZRaCB1_eSEHcO~hLd;6;+DTw?M{cYB6(hRay3c5+ z^Q7gVjhM)bk@tRLODObg)fJlcZDd9^%REx=mDb%u1w5WW4URe!kIuC;_Hu*V(TRW( zM_IvDS38qQnmV&xNuKW$?VEUv%A~9c zN)mDaz{wzIsm?mk$`lMJmLyz96o=(j&j<77r;H*?bki932+2j=kQbhK_s&1asxptX z$8Ot{28=e&cQDUzIS1I|^{#g+mqt^ZnQnNlU@(b%k2@Q;LhB@Cj)RPXDxnD+3ex4; zRArS*Zc^FL9r0Ft=#i8{>pi%Qc5Fsc4{^>8M@)K(fg0LL8Y{xW-x4jm`36F{>5-q8 z+>U~~Ag*&tT+$$ktk!F2oj%?UFrZ}r0AJRsOA;3jvrHtAZB&E|mOZhI=7ig2DXS10X}qZI z#DFwmn6l??2ew5rDPgmL7+n~A!roh5f`!!bR|g~#GxGaXjWff4DRACgcIphn<^#7N zd-2b;UAVW9%)jw8xw(mLm(Ggm5Jszv zp1!pM!#$$KD~};RiIDCazrfYqqX%o3Z2ZSrBWRx1-69H-#Tad&bASdw0Fnptra^f) zYnF^av&7%InA?J^!=~Ynn0kthiq0J*c@|bxa~iQ+1J|0G7Cu~IV#q}-P^MTgKc7H9 z$*0W6&mtK$Ic;5L7xPPJJO2L07FDCd-0`Wh}|l0;~BB$B4qgfnAsKjG>0rE8bV zcd@N2Mp%f^;sMl|M43`p9x>F8{QFf{Rhn5*t>(91FfeI$@;z4s{H!_WnsduPl8itI z*i#!3mG`8MNFjoCx0XnT{{Y@gB!hDC^KwT3jPdV6jh@D?5~hj|I!7$hD3fdsRfD+- z%bs}YR~9$9Z$4-ww~jE(kdd@1ohr!;#NBhfL!YLRARR#;V2G?N{>)D=6+)pgGS^YMwzPk*pGs5=jcOtF&itvkVY@ z>Kd~uEhk`0MtNRICWT0mc5agdE=gPr=eH-;r57?XeU3@3qHC!@wYZ)<`F~su#e0xB zsV23FpM0+{n}M;T3Zgu91afi?TcN=riWI{MBybk!sP66vvj0PcgK^%L0)pf|n z^!n5@+RY`x<=7x0hn0|6dRA?_oV>EOKS8>LKis4BcbYXpL(CmDR4`x%!L3&01+Qz#P!B;_@7G8k~9)+zJ@!IA=?rb zATx7@;EqAT`i}Ue*yyJ@q>m{`E7BY-S2t^{F$?g%;KBOgw9rCDZ$rI`Yh!NU=dhZxD}#!e}cT3kZ+ zQhEOXCA30GV4DGokT4g4*RD_Xs?kc135lT}XIDOCK$cLX=e~H)1L^HWI-d5Xp3Z9J z`J#YD5QgC;VKG_fibWx~QZ=0@4=Gp;|DH z3dX;BE!#moiRF3k_4TJjcU&wkRhS0-;K4!pe@}X`_Q?FXS&_wYH|0u$j$*ZO+}AbqFJT0J6g<78AmI5Zz_g9VH~#p2~&)! z_Rc-(Wrlf#Z?-#of16;EEVG<;Z^+>K`kd3O0+oEl2xcs@za+B)d2HvA(~m*ktwS&# zUSX9Zw3Bp^nFF@cc_8Be6PyAL1_wB-jHT}sRVB4mO{nfvn}aI#TyRHDd(_g+d34Du zn8XWjwM;ODCAu7ujOU6;*u}Zqc!om5e36woJd6X>VB;gx@T4;#xD9D=2B!Mj@ZHAgU{hh zBrlklsZG(D2m}zM_U+%+lVr&(j&(ghQMQn7Np$`3h*!EWZbK>Ik4%m@sif}r8<#31 zb;BEXU`%E+gpj`B{9iEl?fTVwqZ%0lK^4H0aJP+=mSyNT=ol00jt8zPR*K(D)H5Bm z>~`{}%w)YXGcm?+#2=L8{Q(tDNiF7M0y{LGcoIaj;z1i9;oyT_fAhO&Uo|`^Av+3N7&IwHjI7ly|;E+O1hsbC9Zf)tzpbL;6>Wfu1H z2oBsNOP5v!SwZ#o^%bO1!#bB`NuandxgIXO<){ycIGjI3!Poh~Mw}1 zcHFbP>%+;r=MBiuLNY%tDKBhok|mA9O(>T!PL4>9F~~rjFmv-0_;jeenC*kLxR7IN zI>@Z5&G)`gc<+p_)2KC)i@C{Bw3&G~-8?q286=iVg;*gcb8bB_2U?CvZnE&;V8|M2 zLIT_K)VExHef?>WBAncBbde&j538)Z<~S`9{KeD02=O%Hj$M%O5Q|5 zFC|*yc7>)m{nAKVa}(=HEuc3AV@Vq77}UMIjCO^_M+erQaJJB@?zKmGqxlPDfK>I! z^gMuSp}LVJ*&8>QcTIHTEZ$$;8;@>y=l=k&N^r5FZ{}%2?LOE0EYYz~mPa56&#C7) z?ZsC%lSl`iUN@d--Qgn)r;?}FrZHLfHv)MUHicbKj-zm954l^M;ei7LW2dcaEV8RO zE9Xlx20Z&3ttY$J9zeV$UPtVbX}Tnyr>OdygVVk>TUgR^N_S-m;zX)EbR0SD7m%S{d0>vvswr3$-VkMR{(*uFi)cRG%JjL1(>N+hs z(sg8*q<0Iqa3_=LkMOJWOB?RCX*ik|StjK|upc%Xu?N$i$ku9FsCgr4W+^Hi^TwdG za(2f(J?g-;wF?}Q$t}QVk*+?_=1Cf1$Sist&7S!j@xZN=bTXXM>Oos-OR2j_Aa9FLb62c;<|W14eUD>M*W?1~$> z7G^B5Tgt>Y9)}n_XMyR>OC-Y1IAwITWV$%FYjUj8NHPg=$p?&Jfxrjei0*B0%oSsK zAXNrPLnu8-2dL-Jbnneq5yH%E(|k$2i|xkd4Z%6&`+hZr+d3&qEeuGboA-8b#ceDx z86<1{RZN!>9J3wLVON}mLBIe3?`5WFSgz=0kvN%Sm03^GhC%v+&*M?aYj1J}pEjKx z@+naeF$V9(LC-$J+J>^TONF#;u*D+8B2O%=ago5_42)oQp(~D1Qr#93+Dn*bl-hAe%}HaL2WH%o1t<^|WzG-b#wvJZ z2^^AI!7h^)41Z%+05oGG=bzl{Z!Ma*{-!m)y{_ILyC$pD7*Q_zvqC(@VqmiK1aVvNNN zino!l3=I6ceL8VVP+ZKpJkmB5&LD$o$Pez>V<#<#^u=dftcuMV&2Y--(c7Sta;XPA zcJ6;V&@x3Mv760|sB-`; znk1RQX||cLBEdWZ`qj;oXKOhiC|Mh>;5raJPfy0QZphA3<|2YPXFG(GJ0NZ8Bn4EG zbC5{+htrJarW*>%j|_~N+R((|Sgtw4b|PJ0~aacJf$mMQC3kzWuNM(c#rU;^t$0CEq+=GIo z9)x3xwH?aZ7=~fCiWK>tMPDo~Fgtecedv)O@?J-pZ?vmnQ-d2X=fNJ`e+pYT_gj6U zWu4b(6M!~`kPg}FfO_`HrF0i?lN~a`p;p`wr-cgv5%%Fva5MN+114WJk-V~}CS_SxOqd4ZT!1h+Cp`{FLF-r0Lvi!ki>7G_TXdS###%h{ zoc-41e7|2#YD;4@^2Mdv#`2lTRE{o5Zom%w_N`pya%CPwi>PF11H zbA|WlN$c0OO9X;jZ!X>f;LskbYDK2Qk<1G(;c=ASIDA_ZxRy9WDO@HZ*v zj_N@NnyAXcx|0QPBrWBEybbHK0JpEs1GdN{( z3layE6+i$EJAeA~QN)YO0Lrr9>}A?if1J?jG>z3H(kFJe2zQ`=F;{VBBq;|Y88{g| z{e?2&?#%v7w(>2!4!(OwbsNVg2ksRlGmQPCcb223aJV@g zv)+_P6ptKM(0NeXuE^s>D;oOs2a&)4e@enrl8`p3vXG9^qeTUooNk|TZQIG<9)CY` zQXy7%5!(52!zN=XovRoeeK|P%s^Nw*Nrl<g(!!-Y7`c-U&-0vdbd*cLm9Op1^d$ z&PhI;W189(VmWd&Q=bW)`T654BRIrk&|~xG*V?1DO|eK!yN8v!6kohXdV3$ONiDkz zu+m(j!*3BXTdZ4}MmXRR(;oa|J?c26MKDOr@GO!^m=JDYJ9E(kSkZ;}!_WRf^0owMd&Fx<+&++R$dN%j>niv>-s$Y%1xTfuV_ zPQ;C{Tv`~^6NBcozrX;^ZYthmYy)!-LJkNc9Q}PNW?5b)idj{y z<3dJID+VW^Ba_AtJvsbhk_L@j#!^Vb4=5Qh!FmIV(lX{Tsd(r`B$Km5;X)ar3RDop z5O#rqp1}3z^UXM6_ktu0^sgn zy_3P?Bd%#jh#`@XJB4t}qXXv0J$U+6r)DZi$hRby5fL;JOim1Y`6WRZBZ1SC_52sv_`P1$#))xXI;Wu&fefH-B z_2dFT$7)Ai>^IJh66WeL^24_b2@1yq5`L81IefN>Rg8rlw#>wCDtSKKpHEMvMqU>E z+^{rhg;$3-EWPo^2i~j5o>Ii>OG6?y`QpIx#t7$-ah@_gYdJ%h&)UYufJeE#mPqAO zD2%Z?fLCt20q${=&!spCcic@QwZGXJLfsjD(E~taX$P?c5y=NU^r`0yZvzu9 z=8{%o(W?c|r(WLvl%sr@idjKrD#A={W?#dMnxyg>nmeC3$namP!x;od05}95pq{z@Ri>!kN<1wTBJS64M{wR-bj}7b z&Q1?MonuC)WUg1u5Zo(B9FQ4%{$J9yBbqyfl2}?o6qPG+Yqg|dgYuKdKBM27(o$^S zOAY%Njt6fvq-!~EFfr#KarhI{=}R1t@7cLZDzhUqkUY+P#&L}E?L=)Mmf>TK?!s*= z97*?E8QL>|di6e)1-{ttrj3UU4(}|G%p2?Z)>4Nu4bdYox^Lgd6jDRGWy;7*j0O(& z$N*%Vap~_Uf!BUyge6n<%R+Y&Q?qz>Mlv!1j|3nVWTF*Gg^ zv4~Dv=juYY869!Zbgp?*aSO5u>|lyWS`f$k`O>?~p8!#<^za z0~pU0rQ@7K_n3XY(fDzndl25fqG*GwL{KruY;!i12w_;96<36CD$2B^_ z<|v|B3dD@%{?K=)sT}a_TCbC z%@yw#Ik-n-pwX=EBC}}Q%91H2V*W%e7*+lfK_rp~8@S~36>dmlx0&OVkgX32!y#0j zy~xM)G`2zGRi1h7UP8*V`PVG_eTH+#u*Z5^$pD=UK65j(dDvl?)aTduPfuQYS4yWB zsm;$6%Wz8yJW-d}@0QGQ?OnYvNEqkb4VK%+$0hLesli-JkKnn{A*aQ zR1wvbEu{iMZ8goA{m|QM6h$RP?Yo{vIL-%p+yfcMbJnxK+c6+Tu(Nr)m*xl9{c7@- zz{-*A4@#vKCOIK?4aKtAVS+ateqW6`icfE9(MC2PT3~#s#|%1yO29V^p@1WTJA=hW z10!H5D0wBDEt*bN0f_8bx@-e#?dhKX0GCcGR`U+hj*7Yc;3!EW9gaph?@75Cif-ht zcKcGIlvPoTFB}ftsxAWv5uy9Up8IzbpHM!u;S%f!!A>!pAnH5fq~LvX+LLMA7&8C| z+~Xf#T8P5qO`!~GRIWJmr(>tJEg{b*+P6`NU5&vcXE^%z%{5dGi^n{#6(Jmh>Fq`i z?B|Sq+*S$}khdXL4#y05Jc2)wrn{zCF#{(A6H|~51~Kz?s#6EtFo2f_A#e`wZvDE^ z6w?)*i-@YKc9KIJ^``@z9>j4~AqE)4MYo*w1hzfBY3qeupp`87B>de^f3HfpO34&S z!Z#%0+ksNjW1et%s~+h* zwYh6{CPr-Fu5q}1+;D$Ce$@`|>-DL129nw5n3Lv)jY^Y`m4I z6V6EeIR13_?p&E8NR<{O`KR;8nAz!s#z5rr^y8Z2s-G}y_cP{!(bgi(6pX7Pyly~I z+t?m+`Bd;;nMaX(EVnYm8)Wk^EJr%@2f1ZX0Z$O3%s%_M{tW?(qaI3WIfR^_e2$Q*7i z(K7wg4%I#TX0R^q{z>1L{=k6xbN5A1&GG0XF%Iu277nhO%Pyo(snrRV?KS?tfuo?MO>6d z%ut-EbNCLN`d2R|nRc7uDD5M|wjimv$k_h?8v1FxH*98RKR#{QRalPat~%sbH+`nr zM>`l{SZ0Y4QIR*Rw>c~c<ks zI+5EanlN|V<*65R`WPC;_07RE+%%#|10h(+MpQWGKc+`DlOCmdp_)lda9iwU5)w_r zXB!t8`G-Fx!^nJPdv{=|;*s9Mg(uvnPoyE>W06G;KT&=fcEdG702zcri_^P5t0<2ya4C%sRosC2BYRl1d!Z3K_DE23P#{rc*rBu)E<>Q zkz2t$Fir}z+uBmD(#DKB;kf`D@CUs@x)nN{vN>D5J+EPo;%u17SKOy-5&hyj9FCR6 z>Z|3n(!+BzZIf(8m40Q$Nh8;w!2Xr!^6GHJCbLXS8}urp4eSZ#yt?|*OY7UGjU~2# zU9gcu1|hlvs!15fZ_c7pZJvZ`UOJpD>lw7)4r@1aD$O+UTr3yY*1>KW z2S;EI0dBY*4r}>M{{VuKYAk*wSVE60TtRUP+}lXSwuTBaI`!Pg{N}!kCtS4WQ?h5s zXBA_J%_!6FB!0?&!6J2=xA;+__+D1FVL4UVVvFU;HbRW;`_0<~=kX-h^crnm%E})m zJTH{00Ln7pV;pqPuUh;7{{VtncrR1ZybIy?xONXSEVt3c7>YR=apbX4{6aI0!>(J_ zzkV+6j8*{wcvjt2<#`)FyYJT^SIBVl{{U&K`Zj(3Yeiwwj9)}bFRmgURIo-S+^KNU zN#-aczV3`WWL77MptF+J_6*4X0BW>&_FSP=a6#*X!S8`u7SP*HsEUACB4LqW=I9zz3-3j91rw9q~?=b853Z=E}xse7R?sfx1sY&meR-{#(@F;pD8(|Op2a#SdRd+gY!540IsXUa%P%Ek|c?s17_ANq;xg&^&rz{rK%|j&_?7t z7Ws?d2G2dJTS;D77E>(nh#7$qxkhDSf<0*(5w+uuB34;dcQGuWRmO-zAb&O@VSL>* zqnr`YcIT}g%~(C6h+N2<*4O7*ni3I!B|`P&`qN2t9&~CRaU%J#GwnSvF9=GoF*eb=?-F|bMOqCtu~L{Ze9tuCfZM%3hN07vWZL31MG;fa zV<0TRI2bB3$NBW9MRO>Lm9QRsk2C?bN$-l4S`!mWldJBOf(}k|=~SirIv`eJA#hoc z43Is)8meYq!IvXQWn*o1IhdlW8C5oe&rYYdDpyDZGhCgc5i-UT?y`f&6$@^KqmzSQ=Sblp-RaXpy8KsHeoCOz}#^ z_$;xWLe*q;v%2AAmPuUac1o(}zvEIou4c$33rxzphu&WG4RaAMbViaG=O}^FTavz8 zC>welkH(Vf?i(P&P5%ICE~YRS3d`S`S)VaXv9wG8%D((I?wu+V3*Hzaa8aQ}A>|>3 zQ{_h@sbM&uS_)Drqqj))>jy3zgCqcU;@^Utg z#=cekoqTXSQQ>_PPtvbiYySZ3cWck|pDs9AI4ZB7o8`eB2{{0FKUirO`r+ASY*i&y zJ7<<6z?0na3CGsHQzmh%7p}K=^%gNySjomoMfOJ7vA>6H#P?TMj*~aq+Ud7VBV+F| z00FrF04nmI7kGZ^?@83*md@VbYNFv}M+_rYAo9mKJ%&d)`d7TM)WxjQrnRFBt96I% zdTqs{wAT^0_W(Fn@43$)9CB;UJXdorke3$%Gv&&QC|#=i6{!48v8svTpE2& z3``TI^*@$h+o!+>N%41x^#!xHO+HDZc*dW<$!WH!f4%c=Qn_2&e5FnU$&p{QH^g$v%6bZNitqQ2?`4??DaU{e8>EHSK_{{Cy>T7wd9`JzTpRG zCm64!&T$T=7L=RSBgnuyvrn2=)TL+ST(!K?CgTy>R2*lX)iuVQ0F|V;*jnf`k>SDG zpx^`aKDAvfypJe?`3hq{DJ-mikLm6!UJEfaF!`}7N~dbcyPdwZ@l~qo^*zdPv7e^z zc9t;9g_CR z1fBul5!<(4q@aUH($+X6wh+m4wNei)jAj-D1}%_5<>7uKUcDt+uca2jJuUUjv%`f9E^U0Bi_28xhbRE$+G&Gn(8k^&oJ?O+8ZmG z3q|L;{ON1AXxqj*b-?O*J$u)H%XJ;vTnX)OZP++SiHOL}Atgb=la(ZclfWFFmF!x~ z+DQ9UQ@z4mnU@0P0;&xV693rVDQYi*l-y!!{0Aj1V!? z(uuVukKg!vD_M3OM&&z5+Sc7IjBwn9kmcdG2>jrE;q!6z^)>7s4Dep5;(N0DDDhxfZXh04jUOG^{*|rnk_Nb3zHO+!}CnTc&@&#ABg`*9e5Kw35QV2VT9R4-!)`rIB-c*si z)G@4Z5ojSBRB@5G+q|<7J3u3hjyWE^IIbBdBl(vz%&|Di z(sfp+H}(gNh-AF9yD%`2UfNg~RPMp@!ECb?91?iQIP6Z$w~aBhv@JK32IfYTmI^r_ zbOSt}^P1CZPqUz`WmSP)v35!i(zeV17v-PBRfQW z0;fC`Cp`KQ)Y6jB)28OrTE#A6j!6NN=5l2u*wW%^%DA$pAfi4mqs3 z?8VG;w>rMCXM4+=nI&tsGPLr_%_~TH?m5XPzImz_J|T6UK{xM!K+aH>&#&eFHGc9F zCzCMUu|QECer9gx70qfIefk-fPD#v?`HLC0z>-MLM$waiSR7#XCa&Sn6KZHJb$fU& z1QJ7Q0cW_9G~JlN<0SC8Bnuj}Ix#ax$E76m8sdoZx34g>PyaWvtfo$#m;K z+R#SvwXq$;1{=Hd`G=?BT*jxS*{m@^A#H?$0C3!c$J3u$#-urke3vd<>WwHdNM7an-4BL(QSSyOMe0m+ba3&m5joUr2oE z88gDhpywbKIU|AUYBQ~0GSBcDQ z%16!fV>!n_Ij=g_beJA_Z>()3NUfk{XS|op4C5+75C}vZ>J;jW$7ciJ)E>%<^BX2)B0FlQ7C#m&0#`+Oew#=CO&vPx#g8^xG)XX=7NxkPZZ4x#Ris%_}K&GgCObO?4!>jc@ixX6V8PhS6F@ zVlcb0gS56XN#JDHPk6VIrKFc|M(R($Mr4 zvz`lU#YI73G*UPQVA6TOWk6iyj=c8B^~F%qE)wDsHN~t*_ZDoiBy%$e+dWQj*#|sz z_vV=eaVrxBwBi8E*XbKU(CCvUx>5&Tf+{=EMOi zSCf;-KBJFX$+gw(bmU8U8fk6joOy|La?%3i?jt1R4!8rLp1*XH&JSGkSyZT<&PtSIq^wZA@XFd<6E2xHoYx8_f+?aYACki$uI@8C5&Ka91bwV z^d~)YT1ILT3{$*rkErzfn``?yBPLftw;LaF=Quo%fAgBklf$#M;g;Ou#rP2B#;n=KPesmn>FLt6ZahzGaLTjgR@NCB-P$lga(T(`+XL%dJ=cot)TR`Y z^05BsZKIt2HFxDk{E|C+E7rNYp3QDmQyx^R(Uy;EpY?&17WsP> z`L7)AzIf*#o)6_*wuj=~Hs4l)ONWTVBy7H1VEydp1mN(0rFz16lTUr3#}SD*`#$VL z97pSx;BoxxDL!?$)F%_nHID#X+|NC<5=G}E4J?xY1VQ`05EKR@C_59C=ifY6j-5AF z(XS?+=HBY^D5Or5C|iHK<1NCx4v78i%DMA-%q!7`#+R%BMu6Jj0ncuf&Dd}4jq+K-*0Cx^r7hHP94*R#2|p|amGQ$ zM>UtO=n_qNb$4R+^2C7UToxOF+mKX@Fg%Xg7&+-&ex0Q1${u-M;GvDNJaVuhx{Ugc z*!RtJ5bBo}X|{5J&OSwA4#MU=K~B*nKZ$;s|1~c&0H;=f@i*#Bv5KPBIAU2s~i+u7x8dPRi#^q*z9> zUCk}LNe#hPfi`~g-;(D!_zLP<-2nJXT%Gui2rA#Im@YtTfAaxSrC%jnN)+gcHo{d?mo3$Sj}`d%?id_bZ)7;YmAH$ zka#1fwQ1W3<42Y_;%waT@-dNs$0wlRl1@3m#d-3yTQhLI%hq$M&aPA|TU&>Sj1?oM zG2hb$q!(~9&os8P%BqE+ja_4H(hg`a`kQB#9a*PuXOVGD+u*;N!RX70lVNxP|Uyl1b&gxoIbz zrYyy~$u+V>%Gr+uu?HY>Ivim40P)Rqro_F|thdeQn#F_MnG{B4 zKQS05jPv|8QuU;0=4ORJB9#<0ZqXSOH(X;QIR5||d?rD7 z6#@@2JiJK|bq$>EDrvAoHLMRF;#orNC=bjJTCrzy8%mSqA`$NMBqKY3I6k-|AI`FF z?240`xv?#o3ev?RHNCSpmAOP@fKN~f9{9=qD$T60?rEilD_KGTJ;-9BL)e~rrvd?EJ4+!jTPV?dn7@#(2xrZgWDtd8i%M-eC+7qN!CV2 zlghV-7H!d6hKyif4a<|Tp8BhAq zNt4VYcGAy~FmuKZKMYf#G08vK+VU$&%#Hq#@tG1a{47;@Dh_jwxZ|ZoyaZ_CVZ#l| zdXbuz2$jUFxNxvLMw3glH?b$~_v!0O3(UqhV_GzT?GCq!T<(+tv9RgDAQ8?_KEBle zYl!3m)+pdcCt^n#+NmQCgKA&V-E7glEjr|UQW@UUOz8t!N$fnY)I|*6_YC(s35svf!C<0<+zayjVTtf zz@y4piDMxkdJg?Ydv~j{3_w20Puis2=Q|M5s^c$pntSfTqVEmZ799(GsCbBQr7RIOhYAlh|bR6()R}b&u?; z0u&fw836Ogw;+m)?nwg&F*VBtfl@+3;Bp7oJom17tCZ@dT0<+Ty0|`Hk_ts`=PWVM z_Z;>9c&O6>{KgJdqCdSuv^ILE_ZjDo;+907-S)}30>6fW%U`4F^g zAo)l+=yTL{!KR>s^((}FVI#v2mkdE;ffS67et*NISY(P=ZURj9la-7{IVeK( z!gTfLt~>Ek*}O>{vPl)dd7{KG6W}ZN&PU9paxgK}9@QLB$uV|fB#tr*DbE6-+{aeN zv@a2051MzbK;Sa*&*Xp4TA0l;w7W&RHAj zgU&sAR^1Ib;}%aOG0o*(nS^Z{f~W&1Cj?;Qf;s4Yk5Nm-xM#yM$q>krQp7RpewjQD z+zPj66mt163rXiH!*0dhl75FhYK6d`GC=H+<92P8j#PCV{)6afa%p*!8S26|jY~P) zAA2&Ao0Vh-kEqAn4F4N8xhhBPj=~2Q^!{&g*$l$AN$O}#l5m{k&e<`@y_#24tkEJX(M%~cEZ1Tqr zJgv&5SJ1FL7445wJt{rkV)<3HMP|2`&NDT``C+r<0HbpHbUgO_Yf9P`xOp-mjx>px zRjw6Rap<5EoR9FT?l&q(c9)i6x)|~pFMM?z)E8EfM$EFqE#16Mt|hyGD=6(D0FW?o z$USjSshiN6214$tN8@r>!Nd(gvIXEOAB(q)ge}&tFU&{Yxe7M4bqwbzMpHrT5p7mN;py5Fpe-r);^ge4Eu_1GBTVRY)d#LSd!&ok>T9S zpD6ii#B?X7M;ugTCt2Jivnv)pP}~B>r-Gw^arcSO_m8bjBqgr@0JI?1u5E8wBxN>A z-e%$t3>yOtoDAGCa=#A8yqKK}sW zNSh~+hmKW}R!|(sc5MR~3)3UH>&;wy2fLMgu+ja{@Jg7XFj#9(X#e^S;s|dB&{?pcN8|kjtsk)Gjr1!KmBToC3Zeg^BJLyc10Xu zDIGmJkLz9JdQ?rlELJC3CgOEmsXY%P(-^C8ct$DZ5Xj9dl1sh2vi=+pe+q*M^4;oi zcPJy7k>>KFaIHJc2#tLS?}3_2T|Vme=15}7GQ4|GoRWu}^xzT=dJp^}5GzEiu3?SB zqChgldz0yk>!P%^v{)jERLrQQnGiE6KD>16`Bt9Q^7)Q6R4t+AFX8L9fu(q3f;DDo z8Fv`h)NVb8zpY)1!q?lP3d+`NGPTNV8`~i8rz0M@=k?8cjJ9e(f<|nSzyzo(=~gi| zmkel* zzFg{A_k+7{LxMVU&0Ll+pZfi~}aBdHjtQrCgbF_O%3%yiv8+43>mNGcO zcKTNIrK%=U^CuTEqg+VDjjA?CakX>Y`ig_gW-hUBIRTuxKQRRV06u>@fh0!213xmC zP&)yPeGk1#mkzOE&CHGo^CXCvE z^Y!$rHuGlQSAos2IZF3r4FVU%2b>2?*9J%$bltz<0>iq{glqmjMH z&l&5}G+NA-`Ue$=TOI2)DR zvu7aSlaJD+lp*rBI4%?jcISlj$M{onY|Y9=QzHObV`-TgxsL#oo;W|1GU_MT(@87a zf-n@h+q84Q>CdlTJ*vw(C(5c-*PZ3QRvwtg`OmdIh03h2B!h_C%fKWrUNPyWQyADQ*-%~NEOU`@=o z4$CNCAg)-qxB10GmC)q5i6x#nOWb?*xxO3ETo;y@6P@O9jb8#1vozaMm zP6-3>?cW~f-nDJ*72z&rD9Wdij12z(hxMvAk*R28mR4s)EBmGquI%+Aox=q2>sHg} zk7&APfT`T8mBAy7bU7UJ?N+pAJgG9Z+ZIo=A2LN@AMf8EH(dT$&rajst3~9+6s1@+ z+YSy7C(^IYIE@bFZzUqwuD>%beFk&RIU}dzSeFiyqOGig2L*}VpaU4{Nj(p0nI`0P z^I9aATOA{gStByI-5SM`6^~FGIXLZ~e_F>wxmG7w;as)Niq2$dWb$7{{Wv#!M)Yz(}OSBQRTR{WRm9Q)h3V3&nJ*@-49}O*1N|Mvcj?x z98CwA074x>1duV2kC=2g;O7;~>x*kNPi+hr6UOo+jkUgIY#qQJgK;_JamPG!@%i2c zH7HA$NB5ZOc>+nx!b!`Q~lHHYKloCi`jE;vR+r4}#<4@VEU2RDJ0ASiJ+6ByO z3}v1*&&%?UQ^y_6eW?zqas8lWd##eq3nY_ACJL$HhVG;?oF81){;-nYX;Z9Hz!4lb z?*Pn={nhWrGtUF+YvS^J{{S({@jUb=X1Y7s{Ej?zIZjJg@;^9jyfb^?JwD?0_2yY; zib(N-dm@Q zNJ!&>Vwy$j1_{7p!Nzg#Uc+VM6t_!+v(2)Ejb(=S4H}gL=OADnbCNxAn)z48em%O- zWR}~=drM=t%wRJZU`_`dl09+Xj`iglpT~QfaSAjr$27k!todbZAG`_9FnA;YEhP-*JJYR(J0iEr7cg;omgo%){{?n_IRhdjQK+5Rgtlr?oe`6XQn%SO@3(n zM6$Z@*NJX!BEOc>*6#XAn>VIJknZRQ@R5^%dm8C1ek$uawZ*-x*CcHuEYYZDRVQ-| z$B?H0V07ZWvqAWI7mM$-`R(^e-W2n@o z<0tbzc+k9g;?-+Nkr_}bbsn^5*7_Ws_9a;9WY|qP~{)VLLl7 zk|I@D+x_g4z>i_n*VJK^ppM)y9UjA0zVfEMhHX0C+s(^4^3)TMcy^gmPKtR(AlyXe2I4SyAU zMDX5~Yv$V8U$yGYBuz|QsI!p|NWy*K>Um~75Wo&WHO1(DEV3M>Bf0K-*F`#Zj^BCxA;VJTp&!>)eBJRs!xt7ex3bw@-CQ)$ zv)kMowpjT9Iu3qp4Dfg*urdvLKf&wWBUsU3lU0uPDa@W()2<|sdZ_Ba;NYBO1D+2f zwQ`;_)^!W5UhhV`TVEqiftKCMFqk$D@0cCCNyixeAHuwoL)P^xJx(@}+Z&j@!nV~> z(BzIWf=@NZxw+Z;B@527?0rpfuC1JxR)z`KHQ0(ExpiH~3UH(4>&g61FCYcrO$VnuJ0O5BKIXNH`)1l-F;;(*Wev6dTe#>K8UmAFQFTb-R z)9uzcqYrg)w1$<54tc6_lGyL5fx=E{xoUj>00+Y>Eoa19ZmagylG-^Vk>#~#Sle*4;W?5D{1^Y~IGODjZ>IXso9V?8~Ae!{rY1a2QQb%eGHTLjM4*k$~D&xC0qKDaaWa z^yuPbqP0C7HdRuklxkbZ@i+KYt!diqwsAB?Wrj~K_Dvp3h+}QaH%iJ%sQIyiLEzV= z{3z0*(dE_bH9@>-tUSbuKQUTB-zmm=7QxS9&3z5w{{Ru`df$g;W;cxRz>FsD7xxyrD&O6)kI%8QMYVb32N+YduI;$_o2l#8y}TYa zq~*(N9n>&%aP=QF_4GXJRq;NXsQ8}cH5(Wvk4(O0)1@G+hC!05pnc#*a(TuDcKUU! z66yEyUfRNz7gDs36zuqnIL2}JiVw%7dHuhJd`JDIYp7r7o=kVL8;z6943Uz0Fi=L} z&mP0EuSW4X@dUbd%NSbP&-*+^9jC;Y=W_JnSQGi0`#MphT9j06aprX}(t?a0wmvTL zv=*aSx`Rr)X)P_pjRH$@WZTaHa!$}Y4&S9_cyCF#*L7&c)$f}#%r*^0Lq#Vsk^(m(Csy5j&pq_&FO72J7+~(c!WR%!eHZYB$8RO$F>0V zmKiH(d9LPvVd&}-x^SuUvW86A98rksT%TV~z2Kg$V(^R>(WMlj&ZC z;GYmlVW?bN>Q2IIn4>2>Rd^ZggScXrD=wWlH*HMu`F!Zodfk=$b?{GCZ?tMQ{v)?- zkMijkF-UJNV+0h~K-i^$$t*#@IO;3qoo36$x>UbtwQH!1R}v&KM-yz3j#msnhyk4Q zk6xAf1L7@LL;lX+Z*_SM%y75bq@M7~rMqny0aWvm*Pl^d4K!Muw-OB$*egZMu%dgxWLQ`t8U9=J_NU{N)q#OnLxF@$HX9BUbzlQd4NiElj^%s@V zWR86*GJ-OJ%P~j6D%r>dc=?ae_&1OIP;?zmKlnvbTYDK0$8#N;mTjc-&u~W`zO~=T zsYg?*50yGo*!s&`)P5dm*P(P(wKCn1sEI1bsz+4=2aq%QR}tb}PF+gPEwqh3IUVkd zR{NAL;y&=m9FRME4_f)(!upP+mnP=NMY`0Q>ne|H0TN9iJGl zCyjLr!#DP1c}XEp?7ce5IAdi~fcOLxy?1tp>C{u!G})2`sRkt`v(SedRYVs~j9CpkNga8Dc` z%Dsw9?K8C~KDzjj-W1ccsP8NS{SXv7qhp@#*xNX{YnFdAa%jX%Tj52{{Z|X)_1ygq%2cZYgnU>2nxv>gc!)c z198C1V=dH@Pd)|l9&2bC=H0EMxSHZ3t91bl8Wqnt&tBXd^sZ_+XD@XI6DMB;_etZ`6+QP}FjU}^NbB=Dly>1`dhqy3lm>q(Wa z8p0-fQroudjgCVB>cIugLbNCwGb5*0h zo`=|AGF4V9n?!ror{ftlsV244v}kVQv$~B|^3L4H<*%t3!Q-g|Ijq@>!7K*;Ic+V= zD7cdB6-eVJC5hzl2WsSWuL-`76_js#tC4h!qTwydvuz)GNfdyY$m#EnmF$+*cE?XG zA=~A~RExjf5}|(a$mnav#8IOg@}F&&;V}3&6%D>;o;CKFsNAz^H}Tsnh!zF0wNR@X z4YB1$0muV$6OwYrB-gEJ1H-c0TiwS$?iE#U8Rq{0mW$T}i~vqgJvi%%`R8@Cnx3fv z3k{qXDGj+RxulFK$sIQ3@<18mzgqT>4C(rMs=bNw?k2YlC^jg{^9~mvk{>DuCkOHd zyxR0rhKJ~Jf~P`0`$s_^ixg@i31eX%p2c?<%LZ)czC!{rSK{$5gDt#LJ)O_Xc_Pm| z3>SIljAMd5ex8}Gc3E_r786{l5iF&g5~BogM{i#B&1!xqv$DImi%+qZI4>iOO3qQf zQb8=FbkDaqIL-;KE=3-P)a6v;h-x(8+x!nq({-C!1DTJK?3;N$ynMq0r@tNR zu+scRCBCYKqVi!AtZ}lES0wS%wRr}G;)pISjqLUc)>e`-Tge)e=18Y4&rQQ4f$g5P zuLiEyGsbOvM`{0F~F&*Rx0`)-Xkrn<0#4>iS$I?B=Yqu1-ZCz zhUrO$5rSjnHe1)H2mb)q@16tkPoEmir(a#!UE1793*8GN92=~xMdsr?um^|avLEAsA zc(ROTQ)BpBG_@R5qxl-B-ei+XpvM}c861+#`M@NeI+KiljZjaPDS(NF7%Xndf=7I3 z@aC;X*1u}E+i5cb=jAh%3&V0iBP;B4$sBP~NXXI>CG#C%l4ZA#1joo6lg0@+!K@^j z-13#AQ)ilF#PWb1231Ix7**gCz!^FE^)(f|EbF^z3IlCESv#12UX`L?7bytb){;dr zjUHa<4nY!pazJoCy~>+Py~L4oTxUC)&EXV)`8IS(*|?WJHz9s>Y>Vx1FViPp&ic z_Nm(KW{%1WSr#~m4K3E@C0GN6+m1mw$?L$yVqFt+6euKRX%UQ`a_nYry_1}C#xeS2 z)aG#($iQ(lhBl0-!ToOw31Bwr-$tl$W@hGb#HEmAoI_+y+U&H(q$Kgp;Y$}+f2u@gok5-3&M&QE+1 z*nXm?is9b`Ac{$|=Eo|Pb;om_06j77Rhq(UHs2-vmHz5JCBRWhsctBI! z2yT73Bc8Qm_fWvGT*GoL?tuGmlQ;*=9389&2P1+;N8o90B$Dp#FEPm6#}`)w$(ARp zcRuyV>`dhw6r=M2xdH}faK3A_KnVHW#(x2k>PM|hEIvfSSYAjk7;ROF14p!iaC6x7 z!1eZ_gs{A*N0|FrlowKKEnZkplhpB9HExAR+(`_E(JoxGvhO7MY{*ZR z4}LpvDlsUJ4>t1eDySRsS$lE#AJV6~x`r6-rhqy-sPbcx2x7dRK^X@pp{im+FCqJ4 zG?63=zsQ9AvJ=9A$s?Xyj_07Qqbqef6v>&b#PLK7tsBKA`Sz-Xld9xo@JAn7nGzEe zXcR>=D|zy&1!g>RpI(DLl}c5DNaP7Lut@wi7?JF8(<3LEw;XfDh@^kF38Gf}X7JK8 zd#_MWUY|(waWl-sm(OB`P?UD+v| z^JN?Xxw`zg>C^o6t)IM%{gb}NjOzv>iO7-@D|y)gOqc{?j{W}t{dEfhcA~2=2jxW= z0lI&MLm?5gSYI_8Eh`Lu?YKYEq@GKWGZtwZ%vF)3oA0*ndGF0fBCvZeA*&_av8;DQ z7q^tKI1C6m&I#v^Dob^@S>=lMTd%g<#tpNq4A8V=uIKxzc^C(;K9tLEI5dUvER6${ zNitEFINOj$4?PA6!KXq6ZQPqt1F9V{s?xpIV+kNfvF;G>dM*rv#5OHeJC; zIT-%{AFVMG292b|ghf8pM#&1f{Q)`YO_60qia#JRnh@nf0nuDRr{}f_;wUO&DB}BN2=`k%q>8>jFE{tf8cdV`D6^nA$-j zg?5t!6M#TvJKHqRK~ajh8tIC6qeH)cYBL&THJ#gx&~Hp&nnpr z2<&+Eqez`JsW^?5nWT)h%3H+>D%!o{vq>{AJ0lp|$=q;HKu09i*xKYI7t%p-6|Bt3 z_SOJK%s%i3)B*_};*vX^_mLI|ZK2rm&oK)aQhslLlzU^QI@53BG0Q7An6b!9M-J?U zZ0CWT0zvEk6s+G+sG2K9uo3dGmFGB9@~Kq>@!OG;$EUSAXcv1dPa|yIzj}bA_9S-4 zPsiSsuP2CG#t?3jFvCA92+vX92mb)AQ!TyfAevDavXVj_{PhztZkSx|Zk>7$#+oya zyvpBYm4&3V^IfU#S?zYX>)d?qM2{i`KiLn&C4eOg_kvp<=2? z&U&7w_55i$Hq2|(O<4j=i8~oBQEa05VV>L)v5va{B%Uxh`c;LIOpE0Qo*S1N45_us zOsUp;^#Eox-w%LMZ znj_^ezCh?YQ#K!u;^VHMKaAhnB`L_ zoj?(T(5^B{p1Jovl=-D^ChkZ|;U#U^Cuv-BREe717&JmfK)H~8)n9+1IQ*(;kQKy+ zOR(xgeUNR#5K8U`k~jcD-^0A`9tiLMoQ%1_v^tP#8f5GA@UI( zF?F9dX?O*flY_?~AFVJ(SU`xXWQcCKE(R&+OwQFhboe0)x48S0vjpkak%-)u1Js!_4UUiKIWYBY9>Fjn~y%#ZW*Gr^G}wn zGIO+?WOMnST4O^Bm2ykO(cB;;T2?VN=Ni;}4Qln{A;A7vRq-Bl>t^}!4LM~^LsVUF1&By`F2sa`x=#`kihv%JlL6rpyh9A!s1_dd1MmCY(w<=D9tg<2P3 zYjE)5K_fsJN$LSpk(KGrLC3hHv@r=T6B)UY#Eken06Kbi?@fv^6cM*1ouG)xAdkzo zYDbDSl4#^-hwTJrSg_2z<0Bx0`2KZ`RTmvjHC4((7TQUK?<1^DDgx@#7H2sa2s#7K za(z8mH$h3~|WBf3q1X2Y+6D zDdGlMAagL9(lh~yICftAjtAvf!7gpjMwD+7<*6dpkt=sE4{Ots8&G`B%+;+Jv|M%7=uJ9p3Wt$nm&H%>i_t8*Z^TbWl2 zZ5r>KxNXP2atI)w^WKZYERaU=zYilRSk5;uU(j*+de!;vt=1-n7Lg)JHpv#yrA`SL z&u@CAYb#1hGXoPLETkNcf1kh7uI-%7amM`L}0jdx08@cO;eDgWHb$e_HCK zwR#;i{nGl~!y-u=ksZl*-5~&}IXL#|{&=Zm`!Jr)OR+5RKxAe}W)P9z?+`|K;2!l9 zDz-8msu?c{7a~O5#DB7Ssm>040SB!%@<|G`eoHl~Al$Pz?%GUnK;Z6P4tiw%6}xGh z-$4T0Txt?s$+@C(*)5I7Jvi!qwKOut2bnaM4C?Gm!**HzY~&U=4W2mZ`Owfy5{2_3 zMTiaW%SZ?ug(E6d_4VLlrMe6)gpq(DclqO!=4I|r;(89;dQ_b9YUCF($12=6kvy*> zedxeuX5fL6M}JC=$rtQ`Rs~;h%y}h?XZ)H-Bt%5DTfKy#Ww(vEIL6UJ{n4~AVei)m+NF-*$s4djD9gf*&EIx{$mQqUKfJq0AjgMZ3H4GUR zOCWa*w3%2SEsoh9o~F9uwKhpgRtrd_Huqj+uM=IS;R2kh$TNffaDSCg6mnd}51S&R zSsyXtShBK5kC}_-{75FP(D*#E^M@W}j~4OgCo)ptJB)-d4!oT9 zt1#Prs_Ne5M8-%`M%(j721Y(*`Q`@EW+f# zvOu|$Ewq*+Y3O=qJQKn6sW&#ynN}w!46FfW9;4Gg*WR<_FB8RS7Uz~cgCHQUKK<&+ z`S@o2@}WIQR_BlN?L?<@o>b(zmbDG-cvTiiqbVCF+9lm0kUnf=$J z)F|DXLqtUjGqhs?!P>5|MgeB%I(0oc{QA`yHp%vskOz%fhE(zgdeDkjfx?+2SYeEn zWwlmjleT(s)2B?HDUA{&D(YSqmG?M_12b;={c5=x6(ubQqm?DhDhoBbhHa7owNFBQ zLF9c;wMjW=gqBz?!b!FpR|Sa2bBu6v*yn@lDl2gbQxuMT)yC!@D-oVEQ!eO8Qln8C^QscE4?GGy~ivD^8n1U8a0eC@fFVUM_6l6K?Qo(Da1OD!;V5~;RU z{o!Cv^#JtbcjrG^mKRr#GRwKceBpUe52vrzqPUQ(h@ng6aE=gdQ`jD!l@eFzU$S8( zw8fTa?5-9F<2kxu7BW2tIq%-7!()q^i*dX_s~n8cl37&b3=hw*rC&OOtaHcaO2S4g z(J>^Fdf@$feqE`N$&&Jt6p z3olh}I(yZxBHC!~=AQ;QI6JKwypLoI0Pq zo_xkRJcHK<@T@0WQfo_7J!7|uH`^1e62O~5h^sI>jDyI?#Y|*a;0p3aO3qn!Aq>1@ zlhJ`42W%RpELW{G!yByQQTx55Fk*QnyNqA~{xtaE*xO9cwLvZm5;mTn;a3H8b4H?4 zWZ{y|PAz z_U}$I8C3j;#kX$2`D&H0AR}s?{{a1Jk(vmm+OkOgVyI!UnM*EmbBuHO z)KjsVONrNdT}r3QX!^$k}SyP{Ydz6sA|#+k!Lvs+&P17v4JzQRW#9zrDbcE*UMP$RT(5D50+C6kMrni z!WUT9Le7Kb+aWykJ%2OD(xOO~*%ij((h<5W5ZR|sF&2gI2mUD06x^z+7~lx zL}pwe5^WPRNhDG^l5gUE>`$+M#;-S+@xyH*NfdVr8J6bbaf~nnFOUzeK*n+F$*5qF zCbx}6yk)0TvR%w%9Y#9ilkMqH&jrM>#Tq({BNv5SGb)3OkPk!eTEo z`DOBVC@b=`gWIK8iA2|iIW6Y`Ldy$6N~vShKBA*5ZpiS)WrNF13DI)Q*!1JS`Qn&v z?)ODu8NHDmm2Iumow3GqkhsAaCqGhst8Q4x>rhP-JnIG6jYLc>$@3+6H!k1Qf0I<_%8wD^%_B`kH9qE?SM#WNFd6iKC z-75xVZ`QA3x|2H_ORJlyBr-)19!vlhR$@x$1E?GyPg;%SNaLSsv~xLK&$no7j)T_% zooyU%BF!YovIJ&SxC}!BzyJ>8ImzRWYeb|9k_m$sgk;E|6;>JNt{F~8KmMbGlPM{* zRfQlhMr~mv%I&;tA)BxycgU(fRFFZo7Q~Lswt^PRg**{~({axpn5DN87kK4S2o3wa ztXMQ-rh5a)AAtG@rk>GOa)FlOJBHseI8dE4$ERLvXglsf;C251_2Q>03@E1FIj*FB1d#cGcJc`R=?4ctT1B1^@~C0wqZYbmhz8ul``uU^ z4o|J6Rw#iEpbHP7fU&K%eXf4S39hHJ_O{_;!IrbeZIi}fGf=^Q9 zpiHWzu%MPg6a$m%?bCz(Yc-xhB#7jnDlz0VaTaE7fM9<m)vh2`c_p|n zB7u-V0PS7G=LBbg+p55jl$p|Oyi+WDr9!Q=j-+$=xrCyg$C5>5Zv;{o+dr6r zjF4tMq>Sz7xafVs#~7PJeYCB>{)7gBlZB-%WP+vQ-m2O~Ulk~;RHoH^O(x{;|15kwx=No2Z$NZErbE8&@x zaod5OpdN5((8(fPxm155Xz*2tCvJLo13uK)nQuRN=LwP-{{VWb+luj?J9_l1jVuiL zvXSJ9U_x$85Ty6(itM*4Gm1}SQjy{N9m*Sbk&3nzc+XHtKEFx@QKt=vVnvQitAv(9?&}*u>I8dte8+cHVd;*0kxP8CplI6Q zM}jkI*;xXSklFs}>~rhwRc|i$I>PdVj&@c%P6pwHUI$VJa((^HUAcsjhH zcn2KvKD6^3Ak5?CSNTc7B~*HQd($r7D94)wZs=kP$6*5}zkD2btD`o}b&#n5n%FGf zX@$25ib_?0$;b`Z`-+K!P7jj-M7M!=o`8;+&Ihkw@uK0bBZ}!|TyBkj(bpUt@IeHI z1#m(4ty!8$)GHs{+G+8snH=r_j=iz-5=Uz2_KeMQMnxoFDiybgAb8M(NQMHb^*)%T zfg^7_a0&#wqS(G+QZs>r!BTJzb54#(;|UugKSR^_Pf$B#cNwVW(ymf6*A~vqjkpI= zp@w@NhmLBYH=)YZZ@B^e<{sw}Ng&u^Kl9HS81&9b$mjXhgpci01xZp3(eoft`?baa zBixL7)eE$lE(CGg#_;8gl1nozihBhe2;}uVae-4q7*Oy>D$gnpnkdfa_B?TddVM~W zP2H6kCWzt;9KjmzWGjMB82SW|3C8YEk9+sua9?0;5LR z9$-A=jt)9tWA&(DhEFo(Ra?swZG~hYD<~N(Njxy=fu6OYG;qUej}*e=Y*|pb<&QYQ z=to1_ih4< z@{&$7o^g@hw3JgNPIlb0ItfuOP&%Y!ZwKWYanp*UaOlq(sYsF;56C3MYX}_|(;mI* z@O!wk5r{IwyX^@KqDa+7c?W<-ame*XRiyK9#3DNJ`N)5;$&LKK9=U_GcuuORvmXYPD>66&jzQ431bfNGPB@sNf5Iio1i_t ze=%89s-lTgiJ2e}v`&y8FesK4gmkT|)n#N7L;*8+nasrdnoM4`n zG?0)al*c5n$f~zqPztfflk*e&Jm6$^KJ{P(nM^p0GAgp36?Xdc^fj8CWNUG;u`MO8 z3YcV!MH?1espqeJ1N7pqO&cx5a<#)`$M=o`hUYowo+>7}%8UCSwob2rHn6@V4{vFE4x_pIC4q@G2V zGJ%HHo6TIZk<%QHPtvVIMJaP7b5C?WQHBIyULewDP|QwnM?p(7O%1xGyefRNn}>OZ zD=J{{U4?64??dBah7m zRzI0Y8&5u*@y$MKDCcyHuuE}1<0`0DR0obZ#~pthRkm`@1a=X_EC~eOSDHp(G8{=F zgN_GpUVT3~?d=vLJnZqp(aZ8&Omd-ecM?WV1a!qkZvac1I7E^%#3Tv1$za8a!0Jdj z&sx@;!4q7wvM<@gaz_AXuhO%WTQ{V+NW8mvU`ehoH3nPXF>WWGG;q`P;P6icbDU#$ ze)%?$#9CC1-bo9ODJD<~k<Y-0%vvaq2LAMP}29q^7O8JF3R>-O06A%3zT1!mmF3k^VImss=~> z@Gj0u`GB&k1Jkb}qsywnB#VvCzGQuVWBkQiPm!iVvZ~0;$O4iS4yQc^dVqT8*wQjr za@=>?U9Q!Smz0BVln^SAN#_7{9cob&>?AuJ;3|xaG0u7VAM?~yR`6TP7`cvDkqd=c z++mmlgPy>S{{a1JoJVny1-F`f?cZorIrA~l3V*e1ZpVMshlFPd-$OG)6IMreG~$j2)se(C3glV0u)60P?W82&|xx0bKt8 z`h{guqq(ePRW@2E#r98NuXdI2?d~PPIMCO!CP)O)MgF=18bP5;-{M zsmSNAWA9M9%aSFYG3P0c6hKwMFJD9?xYen5;k^LRmhJS91g<=>-DKhSjH!C46}J< zUT9_>T9DXb(B~YEG0)PRB8#N%J@3#o^6q6^0Hc$&PdFdStptkYcI;zvVg1~qU=>?A zC58!Z0T={xj(EYK_Sj^KRcS-czDq`g24lz_^MFQb+697Xytus9d4}+%M&s#|$F^%; zTQjTK^F)g3NOLFILGt)$yjhgkv0a=zI0+R_07j zKp2h4%wq&??erk`r`!utk)p&Ae8acQQIh>g1oZ$4Nlg>%`B7HN7~_$)#F4Cow9nc z;>d4e_;~`UMavJ%n$?0_pS4P&+!%JrawWug=LgH_k<_sKY9fmzym17LrF(6~rcxLl z!yFv@Q!U9Z@!f=IOl+_`07ktAMm&_f!Xqw)3Wj%zMAHuEX9X&?@*hLq$goP(ck*r{c_g+;t_?|A`Z z=cJoaR1S07uk_-aAueH4bpj|Q#N?Tc$adcE8NtXr1Dr6y86&^AsNsMhk{##w8(hdU z<+Ed;7zZPszPwh1GD#y_GEXsvNk|4p8&!v8Kd(K_LvYf0%;s0QGab^t;ky~Z=bvuA zwYoKG&vLs<3Abq>Pqc3%ddnLw+#i(fJq~%#UI(Q+&Sr)<#C~s+@-ar;mK}K>^wQE> z5EO?;V6%Bd5UtN7jw%$m{o_WFh)W?YBe4o`)SrBI6-lJbJODoq-jxl8^pWHfBrHggQfSzDgp6~J zau*oQXwM7?%PA!$^HqYYhWT^D9(c+Al$4U{XHpJKrvk8*oxoJ{IU8JVL4kW}!e zc1An#>x!Sr8CH1$qi)P)2P4$~0EfLu){)H8BC|Yk%*`>`wL@|DPku4T;+ZTeWQsvD zBMWhhdyBCQZS`Y}FdYYT#WhhUxZ@5}Jxko1i?U~888Z~4Xk+|Mj=1Omt1;Zc3ama%?#nmtUEBa$rU1tT zdee-Z_cV95#c5q0AsLWO4$#WFW8b)sX^uauUdSqs< zT)^H{&y@&OiQ^G=W@GsCQbBJ!+5Mh)Rb_jYjpUAC!ZiaRo<{`n^5>K3lUke&w8-v_ zyzvR4Fq!xIh8<*~N~qjhpr{satjnu+h@Dz6*FWNfNP z2x588J-N>nELUDQUU4DtyH;|0dyj@gCNGv^6VQ!V>vne zuqv;%hfE=7u{3gGAqq(dd2ScXGTZKwG3px`13Yn31ezI)kQNaL7bZcwcUMn8tTquL(Bx(jWAPP@qT89r!-g zNmkTm<{j}$WgAhX$`E@2?freKl+3-0mC2D37V}uKxS1P#Vo#MuNzM;Lo;dw+Qhf1S z&hU@l5_3P=H)TQS6plZOCp`WXmwT4_*D9QrQc2F`0H473r-m*8EQu%DIACzg7|19N zar1Cb2cX47lV(z-!> zBds|Ea7M=FR^IY3MCz!ZbQta5ob{#zftCR270dqs%OsSB3c2sskSm+n&ifduRh9G~ zXB=RMX!h=P+N2i2>Bzyz9eMthMlUSFkxG{ZV7e-@q{nK%InSsckjVC{l3M+eSvOou zW3d5PAzv&A*m3j(AISUFWQye77z=E}jIbFD-D|2VL%I%JkGXAPfI)H!$t*Fh_mT!G z5qbjO?2U)bbJaEJ2c~30r(@lo*%8rKs z6UXC9W)S(SE5cyewlu~|bI)J%`OswM;w%@C7%dV=)+F4@uDiE4QVGdE!;i}(=2pET zMo_BESa$?%InTI1{c5iejz)>CjHo4rxW>_tdwz7DS^yvS3p225ffC@5FabWjF`sHu zS3|lao>hwHWGeH0;KZTY(gV?0@WTXi_;#zmEEg-~Pcp`c%ksGa)Su!RJ#t1mRXCw9 zC`n#51!QOhF_l>30Fb0>OLTq9 z9)E#JIN!1;;k>s`*B z;e#a5%B5B1gF9Y8szAx(pasy?w2LQ=pc2I^d5XKssQ~f#V4C!s2wz}F zK+tYnFj7ci(~n{*bh5OGA)Zwc%_h>(tf98IbC3t89CXLlw_vqCK}&FPu$5-}&7Pco zKgzJ3HFi3cd84tHD;S_+;pUN)?sJA_ApRX{JFT2t1#=v+u5fZkT+=R+NJD^FNX#>a z$x+`wUPdah$@5ocQOINiKPc&dGt<93@mM)C2dgDhBh4R><}_ec`5>@7epS*#YC^ii zHU-C$7#^7GkFWIRuq~sMeVy1dAd!Azg9>x&-=%eS8xCn2(P`g6dosW}qK zqw?Z@O14z)9G2ZyTq?$LF}QG4devA!FEol*8EiXp7xnFqm3wI?Cz1!se!XjaChVR6&{0N2GhgMvBac0bChNM!(r4=TH^;T}Fg`W#TD%C`d9Yz~Z0ItoJSHmfjJ zb}E3JZsVZ*0X14VA1t|0p}tjKPq6<0KmNDDF5m-pmLs6;?rMyZ z;z$M#=G+rMDJ_GXejL@guoSZv+NyG@xz2xD&30crNW|mIJ5cn;Vn_MSXE$bP9$OZ~ zOym~a86*s{MC1ksu^H#_`t_?gIXi&bdkT)<3ZY8L8xD&rgP(DOikyu86;XqfNP03M zAZKXR#`IymM_s3d0_5(yuB6u_)PWy30yxtMjN(};8)SOwkG z4!qKa1$T56nQ=U8D2IOSs7oMywL-?~NnN6ll*=D2_m*ERbNB=N>o-<>#VT@W+b)x# z*x5$~RnkqrTpz-*H3@b(P@*<-^C=^d&=b#b{VMZGAX2hAlM?RUMjMX!7#%tP0QJ`; zB(hH|vF`I7E?Jq_|}_D7tRyLR4#MRJdT;|SXNhPO|*?jX7d#Jg;X=Lp(~xoJqNxyu4_`0WV@0` zggb+6Fos;8ucxhS6A_j*T=|o#ZI7St5ud`E zE``i)u_L5uD&Q3Wd1sD${syYC4QxXqj0rrM&M?7xf$!R@mqPiGsVuGLTgDBDk_9;t z%v$3;w=XHM^Z5=snwlHin|Tp)Y$3RStYzJaRtGzqj9}*&9PoW>I@lYDB6pfd+TIlb z5Dlz7^Pkh!t=xT*C>wKx@}$Bkz)^wN^r@EPHK5d`P#Q?Vk&6koNPhM>$4)y|{hp;G z!3vdCa6fo=1C086d)J&BffIn*2a^2_KS%|$$*7Fbl3;WUYz@9kFV04 zWYacO&h@533vR=veqcc)eQP!BV!0vKL-UfslcN*Yws`6J)8j@+H$n*<1Tvu@XVeUS zR9{Ubamn^$=6ON3h|~lA(y8sp&oynPHm+o9)^*jha>TO|xyCZAxIA^pJmR`Lxo%|JADj`HRLWeCzWF%qnyGK5M;wzi&ek!V z(ctHE4F3Q+olzW(92EW+if40i<;4m_T13gjYC4_Ax4+i89Z$fh3rh(M(nL$D9PR2l zcdu%S>Tx4TQZ^Du%M5->v}kjX2x3mr(C0Mww6$r2+%Q2C1!&NQ$^KZ*I#sB9O~|~{ z-1&-K3QKLH%TFN>$jl0<#|J%u_NuowHkT~X?v@ygC(kzWe5-@swhnRl*V8xp2A4j} z58be0cQ{Zv=e2MeuY|2(StPcJBh1B*kh_*a*OBT-$KmTu(d3GySk@ik>9u0xr@8^3h_B96b{WCXO(FHz$AYbJw56<`w>;6kGKi;HzgUJ zfD0!IhaZzniCy?Cz1?qlRdGg~v;yDnz( z8H8l|kEtA1HT>3s;$akTEIXqSNa$6R4F3QQNEyh_)9XWLV^m-s9~I zt+=$?l}|x{I2re?T|2|;Zdv73lqt)x3yl8&I_m6aoEwOpWH#*>U=)?wJx}@XSvS`r z*)Ce%7jPArASIhUy{M-P$n3M6Y}x1DK1&%id-Vm&LkqRbbh;egY*kc8p6^!H(RN^iZZeg5qBsV+Cy=kGoJpxsmW>f>EV>B zv@L9{Dx86iI3u?_SLY|}Rq(PO2>d(fCd$U_w~?S&ist|xNe8F3e8xzi=_&UFI`6;(QJ_9D7leI`jH`#0IO z1c{c-)-WVk-wZ$`WP&lrd*=F3j}lz+iSQ5YbKq?f_e!~c zI@T+=QFk$jv%00U!5^JAf0@nx5 zo;Co9A8uYa&)+*2sjunF;$DjurwiI%MI7+S11WQYT0#K;XOoO){{Yr&`Sty$dtd+BS9HA5`uBv{_9p|H{Z>*+GW`6G zUqtZ^mu9i0m6Beh@jOs@v9h*KLbep-Fu)*WjPb~?Y4BB>G!pqy{hsH`j^gSIxmGrC zdHGd{CANXUh@0m;b5ayou>^L43vINbh`uST^>FO|EWYiar;+Y_kUO)a(4Ihy7vt-`b_ zda7qTk&upC``GD%d%JHQ-N&Z=k4w5njz!xnr~vYZLVN!J5d-n|ubjLy;#j4eX_H+@ zTg{s?nc2Qpc=NgSP^kVY}bO_1E~IfKlWi6f zZYsPG2+7G9>7PTMmHC1H00kTUj&%P3h#F1bi+n2z$E(=bvAt6wM;wj_VV*mU*drJx zo-torlI9d8hLsFL=DyFd{MU|HoVzmRi&B?cX`%e1UD}eOWD;Ad7X8B!g4z4W*NUYS z&bI7Y$swBB>7!_~m5tQxW%t1cuYA`FKbDiK%Az>s zl}fU<(hh5ey*13$j*o37_RzT&)>%?MCG#60hC?-I+4<1HGC4^aMbWBENo-E= zVh9pkZ+624T=hRnmtmP_wRv_VSt{o{nSP?E+u!fB06$7DZg-Iv zC`NMeH_FTIYiOu85}R9&QT8bziHQ*g&z89>yS6&g`C>^oPQl|6jnTw+WOn^(W!oww zb1+wpkC!JIz)lNu9257~97elOLM9`6Q}? z&pkOG&Yg4iizzPN-bjy_zq#k8eLj_(67o5Vs}?e_+W@=Cy#n6qrlj5 zbB69KIY};~=3}hP?`smtD*1(5aC~J?`R1%!Ng6MfH#N{!Sj$8iO7ow+oE-XAVR%fg z>fU5X%w<(@q%~-n;)z7A1`;)3%AtcPKBBYdXwFgQLKqq-?aYw_GJ<$c6qDYntP;y| zOpX4t;wTgyT=bU;PvkV?e&AEdl zPsck+W6fsi#Cuc_(M#40vt@2Bh$`$>3u+B;nX z#G0a6>eiOQWAfc%6G%W-W*@{hf=JH?2OL-K=Y{?t==zGmJ*K5$b!_&n2{9^7!Q=!v z`F?J!It==p{{RSjM~Lq9=@#O~=18tuQ?_{IDVvvL5z!Tg#1rGIXZ4R{k;lfm#$746=kqscLmEZw7x zRk8BQKwfwwkVwt}86)xk0OHr}`SC-=_7Q0I`iZLYM&If`^TQ~F7(?;WL-89Y$GcP=bq=EUsI1t`4ZqePXkNx#c*9?U^go;=O2Y_ zyz;I*!@RI%^Id>DPw_QlG_hRB>honHE9LoQe67>BLtNFXbHy&jK`6~4^lE(A=0;-C zs|5!$@RxP7r9$sv!@v*1Wfb9sT$(Z(DCp^bf+`zrp=y4S_u6Wb^D zMyYdYZ#-@Gt9Sv8dG1K+GBM40Re4eDVWR3-`m6p4_4_~1t@zsC#amG$!l*2l4rup<{#o^$IPb(k;ZXelj0$(Tg7c}V;7$+uOiztQ>!$L4g(R9 zf_VUX0Baf;CnFwsUiMYMPmDnGZP0h4X#d$P_c%a)HP)&fZk(`cl zF_HOKjOzM>Ur#ZTGdyw@+_FkzDmwsi`qRX?(_FXI{fmY8cC97NQ&^b##;<>SEyvn4 z>zJDEJt#=W8F&?AOq-Y zLfcB3-rn5Uo2aMrr2AvD86$=k&gN$)J90vRK7awmY*{-((8XmJ+EK#BWr{V+OdAI$ zsRPh-=DgQk_dip^(^00Q6=L>-;icB~U6Lkao^oP@UkW}Oc#Bfhmh$^gFnLD>Bg~2cJRUghpU2+6 zMEogXKA&!uvpm5fKPi$Syf!_60=WnupYsdM@!c+D%+IQVYxxn+Q?cLErrRWfXi_+Ma7 zIuBarZ`I`zT*oWV=163NC>2y5gC5@g^|`4?E+>4t%&8dN5-Db1$EQEix%YUZwrC=e z%z!pG9zzbE-1}52j^{j7p!7N0`DKwFC~kt8Vp#1h?q+EoNx5bK@y2pO_8rbMRqf;n zaI%&}Sm6VJ8AA>ZcmtNt{{UXBO>SbD=Z)mbI_3bYwXziTBOr`pgWtYu67tbxc6kJ- z1fpoim{maOgNy<>&JVYsr#AZ=#mSwFSMFn-T@>wvY?Vl8*r~`>_Z$*^$I_i;B3w%= zP8LRHX$*@Q`^P*Ui14^f|E?fBxkTzRAti-I_dyO^x*!{- zCXs~Gu^4%Q`IIo=oDfgcdsgnhq_P2U;^3*abc16vDvXni1A)sPzNFWkK?GKJQKYlT zsVr>QsO`7+nc(A)PCNGCV!9faa~r{xwH+;+?Fa1sQa84r{(`KE%srZeCaN!QHvYGJ0fiKTpE64XVes6c*P|Nh?Ne zi91=3@opVR2OxV4@kg)|nmIip3f|;ZyPnXx=>Z(dL&wF;t?W&p%6RoigHC+s>FG zGODX?UD?Pu>G+D>mgalOLQinseY~soytd;pJnko<&peNM(~u%Hy_(Eo&8o=TqZ?UC zI8ZV5&)15A$4a`ohGvdA<&GByT#|OCe)qEH13sjBip@h)qNSQbs<+y=iNAFks`;p= zEOE!7$7*(^4xts0p4DZ9Jc2bKl?A(UcpuWO>UI<9_K!Wf$WmC2h~$zmz&B%#G6ClquU52<&Qgyxta9y$U#DILMxZEE5ieeQq}$myE# ze-L=2-On6?`tR%(v54SFvmk~)L>(1Nl24{jwP!pxy3OTX@}7@lr|B`6kx^JhGPIH) zDp`+GSalsR4^PIbYIX>2rFhvqutPx>3kEs*V>QTlOIDQ-Snpsd&vn9r zPjE3_g>JG#aFCd!ggkE2i@Z6KHXkWd!BQIpA5JmNVyPsxXP-K)*L!qP~(WQ`}xE^Wg|fq&J;Mmr3SeR=2URhITiB8k*Iay+sWvA9sIpd4o$ z^&IohJmWQQ!xpp2V{DL12$)A7obE$Lt-C!q$R3dp23J<#jl+-+ zTxS^i)|8df(8l!PCV2GMQzw}kMyf-z2-x|7nDytkJ-SyXb#-cO!mWs{@2x=XUnD=}cejx+u~^{boYR$7};alWP7eOlu35hDP%5XKsR^ho1a!8jw#QMrZ& zes1RjgH?4{VYnY@zgJa~;xLogP3K712Vw{^2n6IaGb!~I@ zkfZ}55*1ke<>UjEIa7|{PQrZ5OOB(dj#j`iYS5N#y4*DqtYWMTrY znk|V{R^vN~jgMtqOn(>W#C)67M0DDOsr)e{) z7FgdrHhA0*1GieGQNd_&wBt2>k1Nz{E}G^z7TM(cG}0L-i0%QyjEwtZ{5sdCS?eNe zV1b=32vI)Bu+1g_9Wl7z4o~!|nnssrsRDk|w^tB52<3)yxoy1UamYE~@x^M}>5r%C zL_9xewh`h;ax%x*^v}IYsW$azY-LZC_dR>U8kVVOV}&m#Vqe zYtrlsTNx%Wr;#nfD?0qlxg3+}_*aeTl0#{8Ya+#TmUiyUGcHVO+-)bg$?5OyUWIS2 zS=q3P8LO}5CTDE4J7!oB<0rbqD*vVB_3+))lnAH*&D3d}94R1`8d-O=?Td+~CvM~XZGoJO_8)<*{flfONN0xe zBn%~JLk}$U=OA_GrC|$)neHKSyHqYhf&sweJPt=s&)%lAkX(6@m?XA!3_P;ivPW@( zG7d5U{HvLy->KIbwvLw0*vD?s2aE6+CyNd!_NDQQQ`l~6Zz&-wSIC1g$YD_E#9GtOiR zU*|-~<2VHSWPw`tr^=dZcz=Qcmza_pC$HC>_N-P%dxeG>kqjkS=D0#tPI3VpWK`y1 zZts_h6^|xol1v-}>DWx8gN&##Wj@<#{kEKs{AC+qZI zt@0=VRacKdIqT0k&#h9L&hAucB9Ctk8n{5@*j6K0wWQo4& zxd$Ik{W|{ujcSu@RcWg;rLcXlNL5`zL{7})H{)DCiSNa(_+prl(8m1bwz)ZBliRQz zv5tUOS}urIRCyLd<)n6!s+h!o#Bv65PI&k2jGqqpsjFUDq%qmUBS|B)Vmo*@GcoD> z{*}#%m$HMA>+seA<{7LhcRicJS2s;;^2*Hitfyl#;hR59{*~x<{4{Q^o8U~cGXTKz zf=B7ae3S6&Ue;|M2xUu|nphQOPFn|eEwp3e(1L+;Rud zb4~r#)NKhQ#zSPK+QL|W5E2qFMh`x;`BEVv+(A}#!=r)}0CGC>>q%{NX8DRMJPHf~ zNWoKs{6O$VJ0I&_qG!R%4&fwL8Dj;?TphoDA{ZG5ZaAv57if0JHfCbD{ol$Lob!?G z`qraOnW3LijUkO@RcLMCSo0VkdkO#<^~ZeFFKm3p@|eO|nX???IXs?80Gtt&>G)RAot2Ax#m5j%W0KZ3h$1W8 z#Gtano-hwmGC;}o#Yg0%R}f0F8LixHX`NUrFdsI042<*x)7GdY5%2p!j_Nm5`^j?3 ztihdTsN z`HBF~0Av%2(6)xuLp{V&-_068TuXCq(T&Z{K4MP<;~2p0(zA?UO9~WV?EEXPNhhZR zu6oq!(vL8XLoY|?81(*hw-%!g-Hg*RqTu;vP;nvSA#uiVbI+&KFL`HtDy%K1qkp43 zWO<%o;frHDae$|%C%L2~NeV~h`PhHne7OpJe-70>$c|_LTe(*91{jSXQ5(iV+*!CF zgNy(<=RG-RT`4Of2z-erGQ7e#VU<9)c+Oakr#%l}=TlzG6t@T&nplKuvN8Y>`wpE> zPvUBhIP&osVIM}$Gn{Zo9{lmeS{_u84XDi{ZO6#Mp>PNpBdJ`RXVm)B?jRsr$^!h|S}<@&{{UL6`Cuj$jtTjRUWTVjjnG`hCBp@Z z58S+`=4ZwVj0|!KI5^-R#$_8E(z<(=5_o>kJTf~KaH0mDXjvymg@yRWmj2v-;oYgDF zhs{#c29j26?_rjcl5y+PKcA&AsvCYxd69rzlaeU*cPdI9iB$mmMDdZaPcMKJ4my9I zT9zd-+y{&85-^=(i_M5L7CwM=9{&L0MY`;@Z!$xeWe*^YN~l4=$T|9cKJ@#=k>z5r zNbwRr&haT#`h9-2E(w(vB5SD9VH-mGXN8N+2t7f_=iBS)R0wO2DkNB=SfBUB;UMJj zFh+g3?af=bSF#DZNW%+lk1T4;yU##+9uEZj8qSjNd6Ka{UARS75w7QHF_psL5(ylU z)83M84Ywl9t278vzDDG#D;yJ^fQpPO?FLI^-6U$w5?y(VAI-_!MtH{njPviB7W7Wy z>O>MNGP17b1yKJ02nUh)^T*buhcd}3XA%<5g&#%-B z^z`PYx{4GM$|ARKEt|@kbjgek{{TbR){;j&q$0;7zDq{tR>Drpk1TuogU3p>Z*aR7 z297oJXI;eb#Ya#Ny;alh9K|Eg0TH$uSedq~wg}zFpgd>#)RNqxk`l^UHY!L;0zuAr z{5$dKO8ON^Hp^+{wZgQ?4*AuY=VQ5~lP8%DdiMMWergz!Y2}_L5g=Ye2RQ{#100S) z{$90KVdap=%>qe3bMkE_GI;KJ#YrUV9ICNKRZJhfD#SF4*C#y>ZaV=<%-OpVNepr{ zjAhD3M#)u#cqjG829=8}#ofasaRu_^TAvl#hgV!l%r-MNlQ1L=dn^z;==Rz*9?MQGa9-YNXlF0t_&j50>t{Xisi z^&ZuD#OrEEETnGPB9cJ^JOlJUtyG#HEtO(Y=W**8=hOcH)m;*4*Oy6dkhn-eC8II? z#F5{&DK?SY2yz_EVWfSIuIj)vh`cdeaDV##^ys{-6rChhavXUsMp$Q#+4>*pTk`l` zVJa+4vPP0~Bzw3&#JS_ALONtuLOd}hZDjI>$n*DqnX6ojc4awI?s0xq#FvIOw~;O) zg^!!%x~Ytu5LgUkgNzf;HLqo$NpTmEBD7I)<*W=;srDln^si5X$>WAd)+tI(6VG*E zs>F0GJCHh7+*)IN_df5xl?h9IqJXpzryPuhfhGd3}} zobq;nK7du&)sdPtQ4!w1!Sbq}n9n$&qPBunnI2i0iz2ivs> z2pG?APfuFamD_ww@}euL1_+4zz;(~)KU%@R4rKFVZL1Rvs-*G$AO5Oxv``q5+$-Ek z6GWlB*7GCUM?H^zl+$L+jumB&FzU@a3@a5JfKMC)jy|1DOLG95Y>do5h`PB}-Sr3g z(pV(Ky~9T&(1%|-BO^9?jynE-pK8NXSn7!)Hq*lJ!U}%vOBRo8fq5g2*{ZhC&lH=Z z4!too*f3<54;{&B}nI*XSzTChvMV5wvW}=0BQQk38{?{{Z1t zW>thROPJL*`9?D3$`xfNs4dsHz&$zltuni<9S-G{SN&4s1y4iHO*vhW{K8ZT9EiYS zlY`&#JRhx1Burv1a}!A4J_zA`y{LPT;AJQf$8SDJEO;pom_q}A7<->yooYFZi*7`y z{%bKZxB+~^I|0D&QQBX5vdeEAcUw;4XPbpCPi}Mgn!j-jvLOx(thgp~C<=3)G1nux z>C%LoL~^u@SRjq0o#S~I%TS84frZZ_1F0VMwwVx0Ba$_D3+Cd}J0Z6zx5AsgI56=)1LnTN}kyl z$%Z*IB$3EiNsqdm;Cf@%@T3+nvzH07M+0b$%HaB+!;i|G@3DojR#jN=WDG_IeRJtj z4hfLlN9Bo1Dc|M~zQm{*?bokbrq>de@|B|{Lhg;2GjouCK6=wzQVl5q9$gdQVi2S96rz<=8L5Y)roZ}=6cH*m389^?B%EjcBWL>fa8yMiO z>~r<{Ry4>A1VSJ zPxWmaL6wibdSviV5jgi(ys?wV+`pqSmJhXIE)Mv zgPy!|jCxe_ta1?M?&$W~*>5hQsui@!J zxlwnJmqgt>sc#?*N6bb_vjgq)s7|95q%XYgky%4Vs7Y*`cJ?{ur-m^b$cTvu3%qOt zYcU-^0qa>$3aifLRY{X!BLQBsf9L}ok z9IG0L!Oyla!RyKPC$%*SK@^G|rJ7Qun8p+;?(NCX80U(E6TI8tNhDV+C5Zzu3+s=@ zs!_3(XeA~-DJHsCb`o2uL*)~U?gs#zXE`0KL;FVDtp5PLL-uwn6|`}%aJU?t@yR~F z<4{W~MH?hRi$H;z0o49{b6E{&eB*HwAl`+gO~f*egFlfUg-T7FGkTq6tT72Ybj~TKxeJTD!7bIALnAL#1m#LmwEqAlJn0rsK2XG~%u4xx!m2-nj&ghPz^cw97g3qS zNg4y@AZ@{yoMWdTjMpTtj+IlG%AUp+ide0shT3r~d*+@NWeiky02TlYap{WY=Y?&a zM1m!q$R9K#YK}b)2p-keOL)mDG8QsBGN@zAb?1(`9P#g5o~Jm3?v2_B-5bkbg^{~u zvCxjfy!=%jXtq9w4Si_~nQfgOxf^Xs@9d>(rjEi>7U=%fDG>(R-WF}k&I99*s6FfFpBH?1 z@V&B2;r&v={{T?DdDdwxmBT{JxeJi^R%P745`T#M*X%qindU2&F;{``c=quajzvjH zp95$bea3|(Wvs7OLW6wo302%WfZYy38R^OC)Ss`s1NN)dX(E<*BUmGO0}=}}ch6t* z?^i9nBjI0&4lndu=F@ItxGOb;kOzs2VT%^~-!EXia&mG7Tf4J=1|*Q&Ok&eU73NS@ zMo@i5ah|yyEA=R2J+kH2{j7dpo8|C$xmp%xhs0|y?HdJ+oCyppuq>_?HBpvtnEf~% z$@LOS_{s@VcaFYyIj@HQ01-5=6E2*#W*eK=%yXEq7)Ud?p4iVAAJEs)G0%U0cWQ|n zxQa~3vg2aOA0YP5Fgka~wS4nq@Lx{&VXVce*yNyi!bXF}C%wKZFRKGxN(2Ijfng20}qsrCcg)YsO>5lXEUD8}E2@|+|gX!G57 zHuVT}>)jqxf2T!tbg?jwHjtm+bKfBKuLZY)Uk%(`-rnhYYT4X|SybJ~E@7WJ8&iPF zMtM2G0Areu;vdCpTR#vOXYtHqO|^-h(^c1*@vt@<%tTVj&Ph@@uQ1fSZ(-uNm9Fk? zH3%k|%*m(SeVS>Nv7N3#D#Q$qJM;%Ng*uJZdgy+|!_+EL<&<8J?>fC##L`W4wsGng zG1<#FZ?F=p8#44}<2eAFeNU}je;Hgg#-DAcUbKw|?$k#(A~^EQ$TuDVB=9@2?n$qg z?{v*iU2F8yb?f^}be=VzS#4#OIQKI$ z;fKmj7%=0nIX_DD)Z(J9u73XjkkO3c6P)p0t9;%i)h>*-tRC`NAc`Azj!lJ*(IPf^ z#zzMnbn9Km!mAB7`Wu-Z*G#y(ONEi-nPrM-xeSR9j|UuuKHm)3e_n--xYim?dfL1!x!@|Thv{wE-QVz_52DN953 zoVNoC)Yl?+HT+csdT-BRF4U1fbu?|XlEd!)gO7UgeM-vq_RjM2PrA5~3~JNObqlbC zfys8s1gLGGW50fDpz$87rrmgU=oxQXIj%g&DXYD(z=`v5@?5)sC)wi%~ zx%V_MgOZ3b_e*YWa(O+tue3D1Mom*lwoPU@uJr9)(n+-Ta@PKFi1`;KK?KVd@>J&l z@IeHM{FwN~;N4@u{wuk>k{8k-xiU#+@~~xP?*7p${{VxoE%p6! z#9ryk1U5GArDT#n?*o&_#yIU-;c2>%zhe(?1&wi+e#g-MHrF)2hS~&^+Wn(lgbiGc~!m{Z1 znt+}eEMCLn%dsW`$eQ85kBb| zcNM_njP=1e#w&?W2Wr1)w7g~CYYowkVKlp1JPsHPWPy&Or{iAmo);IEw)f1BZ8Bc6 z+S|@I3zo>*6KEtb$$yyR3+g$@X|;_XP`#JSR*Bfh{*xH;z$6obLBkJG@9$pq8{K=y z!s9AB^<28MU*Yzxuj$w6ZKqt{**)Z|9B@MpJAHyrJ3W1NottMA>F-hovf>eSDErG%G&38$uKP_or-Z=}<$gd@$C^6l9S zfr$t?I3xKFYW3Y` zGUzbNaTHM*Avc#oY?669h~Y~f0q6*?3e-GTJ=UnU?-h;XOhnU2ZcV+!%jkDx1`EeO z-4*Je4Rix8p!3Q5)q7&7vB+6tB=et8J-t1vlj@VHHyFhAE>m-{*^kC}(?O^v{-W0g4LxF)zy7i<14@x&0xsOnc@bx4Sj(n);g zB#nvyIO~#60A$yxT6hjnGW?=w$s01b!nY@(!5I8*+UZ)gjMo}nysKv< zax6BtCq7(qH&Xj>Sx5IruNBQt4;pPWwK{3#b93DD-vnt7_M2NvuMKE7p&^i_r*|Vm zI`Q+3%ZbN`rPH=eXn)+7v!{_nGi&$NWstn{VTWxk28ZzKKqOQf1+9Oo*elwx`04m)#N`ag%I@dAsh%f^trtC(eN zxO41qPC2hqv-okQ*=phAFx#A>+_ZoOanq>mamW7vTDA2g@c#gX(&8whv}aAuUTN7| zaVHIedUfO4yOd>3YPCMI1(Q^ymDZx^9vHIl^?<$xIW6D@KeRKEADB5RI(qZ}0N16^ zv^`r=)ne3bZmje>IqxAs5pp5gGQcWwPaCp8CmHmv7V}-xHCBVnWS>it5hQ4`e(cB? zfL(VSFvdVW#=YjxR=Cogdt8P;>BIYzZNFnf98z6GHByrH3^VF4>c6-$F z#R%Q*crTAHwS6l6p?zxJ(l-+^y1s%*6t`i81fTHw*N9l^TJ83uD#LdmhU(o!f4^wq z2^QkpRFDH5#NhIB2U_|^;!lS}Flm~et~~Xc*;~m;3nX$58zh0>JQ3g0ysJ#tybs~+ zMYTO+O4Fu_X__m0ZxNSRC?|g183~S`vTZLHx1eOP>$G54kYSX?Uv=)*70H9yoChy-vDH9Z0}D^}y+o+pnqVy2h^YM{%a;2+J@9g!anK z8w_w2#?lUX&!Fs0bk(7CtaLrR4ovCAd%78yHW$7kx!tAdo^9395zA?DGppe3AdD^> zAfBDZJJ+J=`hKCKz_7`tO>cb{A7_{V=i9G-zm;ofI(7Yuo0+D!gU?l4!qOyjEPr^2 z*z&E%Rp;0wParV2JWt%Lx9vFa$t z+9*X`e9n(XxV*oNS<7xx7g*LZBQg^q;~Zq*ag*DVT2ttHg}hHBdn3COGBgZI##cRC zsRy^dYscjHlyu38Y1)mlwV$0bG!rZ`M!i^)NF)^;FW?4EbQWGJ)h}U8UP&*U%{0>9 zf>~BUlqZpcoE)6=6~$U!&g}Ov`ED|rQ%NNKN6X*?cdCXm?4D-K(ZIvX4awsm6OMU4 zy*aJRZwl%fMZ4SyE@W6P3~;dBvDjlE5O7G`I#kwLR;_Z8T-tbo;NG*O~Q+&Q^=L^;kLM>NOa& z?YSd(TK@o6lIjBDTdRW`S;w<;Oy9(-{?V>eQqW@2+F0t zsU)G~I~qwND2|L7W6nbpwEV0O82+_mOYmE*ov)F6p%ky#n&1U#4`Nq6an1#LE}y4M zaSOw7J<}z%(2byJSyW>mGT`zt+wcGngqTgeM>14f|s$1Bf1yym>B^m(Pehvl4Glv3g>JgLfV zDf*-I8^ijYz5S~yTuls*^RJr6=0@eSo&e+zMbQ&S|(>QTOllA}ME_v~>qjmq<3gGtnrmBRz+RZo@?w<$nf zgYN*b2j8yK)DLk@$xA^c)z_3)K1@vbQV%>6$Gt;!0dFiwJg4&p_nzZwusA9L`t>=_ zaah!~&zYoLkIFE?_aO?nju_+GtB#oG(yUu<5#Jk`0DY<#@;9QEvJ!dNA^M3`;;%Od#` z2--2~NzWa)_NiGU0p-t`8}T5+G|1dZHtW7i7Br&u~Ci4Mg zI2(HU_aEops!whsfnZbAT45&S>%jZ;huI}d4oCc!3Q{} z-A=Ju$|U)O+e$#Iw1z#%=Zciw&0^ZI8{fh9FC^I9$txJ}Bb-O_kK)fiUMSc;%{9`? zA)TCjjsr6(I3%9A1PWsVuWh%B!X*?EJwnwK2|+={{ZWMO44WEV2HEaT`&=%h}qjM(*OgIdzy|J zY_2@tHr_>o9OfmMd5RR_fNUIO=NShdg+drf5?q#f5C;1+nsxYu$e1CNH*z@`=xe5( zK2K31D|sTgiMsu?N~)c~^%R2Pqn7Dqj}k1KP_HYV`1KT#&XzY&orXZlyK(_J#(z4F z>9(}DH%QTWB(dM}m0wfsiqo3R>VkGIos*$=Zy}?ViI(V*CBqD1Pyl(xTO{KE_p313 zy}@h9Rh!FD(riPvFizZ)+XRli{-Ua-$YPf>hHokb;h3BZk~Xj7l0ffIg6(JlBXjF(C7MAvARV# zMZL*jwPKTfwsctI{o>j~gm+%J1d=yxzy$jA=A)J{p;WmlN5~rmyYPMKuNyKm$poZH zw`7sr0Kz_;j2v_QJ!-|Wn>X_$k{hqw5Ty{ZusH)f{o%m($4bsq(9$$@Gv|p_jEvDv zQ2y+r?p*RcdsN9YB)gh2RZ+Kpbc}k_ZEUY2S(&ZKfHQe7wE1kke=(obRf|ZcxVJZo z@vhg61*?#*%18GO7=Q;S9Czf5%o=hDLQz87O%qx?1ehLh##!1h$|KJh&miZx`gb|c zc7zEB+B~l}I^lzM3=ab*92(Df<4G-=BX=Fms<2s&$=b@<+`C6r zIXMR-k>0Rzie~Vhp6eL!;oe9~vKbp>+<;9aGs*xGvXZhe^I3y#Imc|)h`W194ZFn+ z&4>~LvVokQoCDLpUOnlHY!W!;h}y)P_cUvX7iq}a7d#yE&u-MMCt{P3*=1$4o&*3* za$C)kIMud}*v~`n_4PHHT41uh%(qV_KuM=i%sYP%Zv58n=)^PF!tulAF!Lm2+{)aN z0qVatKMKZncw~aoLJX{TG+}bvk55C6!|PXPb177dMfC|JY{pqvYUS6DU-v9l;RJd$z&Abox7H_Z{o zw$b^rBRdhfizy)bpYxBUR3fzQVRu+AD0o0NXQuAbpxM&#;nT7rZrW{@*|VWDj4Q6w#Gj>{#g<>AjqKLk(_ky zK+R@ISt62qa?(g=jbvSif^pN-d;b81TaNGSg}nI{6vV_VljM~rx2HeKvXrcC7s`zp zVKGS@reNq5OUImir>1?!BlGK7b4fgGUMpw2Qd<_*?yD=de(25s&pe(5YQoDste$al z9oP3s^D$iUkJF!OtoD(cxg(hExsG;hsXJ7E32bB$jQ&~eSn67=$qaMaN#=mAsKIU~ zvm$7==N(2@?;WMOA6|sATZ^@INh6X?&A33A%V6Ml!1nt4)NursR#~Gn{goOhA$f>| zD9H?=c;NiN`t{E>HMuDh%eUtU;wB0il=`1;Kb==Kmc~_QbXS-No>}CO8P*WRMsu|P z08XRus6s;GBQ2~G2r}#E<&~K90Ouir!St(<%l4xcyb#SJ+(NO4?bj?@ume2}IzC0R1ZAuR|3ik`br7xROZWmJ4$vsy5yuP9e&VAx zMrq@e+&dvwZJ7Z~eB_dP9F7Nknym%dw7Ix~2S9~D7Ys5Na6P)5cdf=-Rkc76MkIxi z6C>`7o-y00{Jkowd%X&ik11YsRE6TUwVD|XvD)&HBBA5wVlX-C0OuI@sDsT6i6o#i z+d{jf8TnNAKT>~Mk}xhJF0CwaBDbBffh>Cu>G;%drJ^FFm9eJz{ zUSD@&IZ`H=##IQ!*baJB|`$$zRGmbm->-6td zM3)gx!UMEHVB0m09YqqjdouklBaItlN`Yh`{{VZgGwJVAppoN5Gc0op zVA95!Xw}b7z?^b3$5Y2Onq-%INd9fYGq2hJ8(SGU0N~^6{uKLi@yr@X=i0&9-bXAL zo}8X?Kd9r1eA0~dW)&kV^AkKa>n*Yw)-YX_l4WhOa849A-aajd6F%HSsQD4XP=mk4$^qzILOU5=HKk{i;(1`qllSz5W_j< zx??phjN>LujS`_}g&CEjjwy4E%Zwa>$4+_vbp+Q<16+;nOUTObONNX_a7NzX=LbHA z-jxJOV}Ygf136}q7!{8h>+SURsNTliOUzuXP^og5>z?`ai5F+6n5a@4w>#vZ_>7TvQnk-2608c7(G zY~=i-Kban)nFX{LGhBU(PJ+g7En0cuh^t7a19K8{p5C1*;#tZzz4Y=-(yv^FAoRx= z`qap`8>6`SQRTKiKT9ZZ936lkGP*w#p<{BpeK9uN;hb6v$_te5EswGi!NL0yrtx zC$aXai)o$y(ZLk0<%T(3e5N9Mjv3!-sXpGH{c6>MSeUN#lRSBVHa=gkKBJn+-aOW4 zzC^uNVix8`-!WszQ_grK^TspmD&SR%A+AvjsBrE{+7BgtaDSzCMoLJ=Scx_)l3TsQ z#WPDVfZB3V^Zjd{id31*%*0BCLjagoZkQPR z!vJ&j9kO3E@XK{HOtXZM6we|_<%L{*)jdJT>U~BkwKRjgjV=3OiZHSQCw7)clre1b zI6pQxJqa9vflZohLAkCXhTb_^4GgIQ3PdxW3JN#%kPzi5%pL}c@f z4yOa_fmSUgl2$iS#9ApOXxb*ql?q5C_UEwn_pWM?YhH!UQ%^yYiGI`<%JWw$%!eP}%3$XP~Qyl0^x*X%$j75eS5U$P^Fm z^~Q70{{UK|SC&S(jo`SBD=)dKpDf2Q;FJR-?p~ykkC5-aD|fUb-8&aDio}7&mcc2{JNfT?^kXuZ&S;fTO~_rr7LT9 z9KvPWj!R?iws_mg!36cH%Wlv(wo6j+JhB&f?f?<7>w|;2NaGx1BOU5U?b6w$*>4Wh zjgiExv7iLw13f_FJ?lkPIc^J;vKg8DlN+LiE)+iV{;wTROjIyP-z*C+od^uXjBeeW z0pBAYw80A8+{td_n2-iY7@idVxXoH^IV9#K@(5OS0I_C2raE$e8m$_~D!C&oKImdp z2WqxInD(h{t+NaK%O=ReqxZ-^ucb+hz0%S>v<(WPgjfqRnH;yNz$f~46>+3Ut^B_! zw@Htbv0#51sWdAbDGSNHq;f>CAschmNk3d4#}zCZh1@eo_IM&QV0pe}s?4fXaq_U* z+4t+;twMsm#{{Ix-@1rO7ct4OkYrG$HxR{8pW!&pMP1sZcRLALrpWT20Y|?)kN&r% zMGA|Unmy6T;h3|W1u8S!nvMj81klB2Z*I<4eatymcIP{}!Q&mfR-Vo)p;Lq+%C`)L za$HIlH4MjwSrc*HZt8*q#V zVRLfBf~qm;!5GQ*?LtQgfCMj$0Uw+hSO)eWAI_V0WJ7I@8*wy|8HB60MqioS2|9Xp z_5A3SpH7&UA_skedCVe;}>6lAd{sW{F@rB|9k9Hwae_-9bW%C{Is zQg9VO%m#Fa~Dt-5bCNFRN;Rs;`}j+p!hTCXHz5%TXyr9M-E#^OCn^N;h^ zqAjLWCCVf(a4udc<7;J+H$r7!^^4e#sN_|{3=4-cBbSYlZIm33Mm!GvFne=ZGC*RT z-Q*1#BW5OITg*K$PXu%8fzzd1SoreU#OocfF}r6azah_G%D20*GP^|?AZaFoNUda; zi-l=YCJP~6g;bmYp1CzFf@v?!xk%%*ZJ6^WP)mOnNXTvnZ$nnl%kslKV1|jX>&QIk zocA1b^sLpiV->^!j1u{*s~w{#UnF-8$R61Dtfh9%DO8Ml8YK*kBqlW2SBxM71E0?V zn)Z`I(gzu9nS8_nzGhMeHx8k?jAZeOv9twKA!$qnW8EG0*n0p*fTT@>V# zfsFqEz3W;&R*9!qmPM#p*lyT1sul>?QaI-%`i_Iw+|y-+n$8)+5iD-T-YFkxZVpsu z9=XA&rV!pM!X4s`<&SfY3XpSw)Z>aLc?eVGi_5vDkqkr@U=K#?*SP1BIT$!RwJ6?q zMzfNd^ATLTq;0o;S(q`x?E{gXnfC8VnP(np&)YR6j}R*E@Iv`;0wC}_;ZfL@L_ zW1%?eJt*tmw_Nea;;h1|*D*?0 zb9qHWU>q)aAIqgPu7vJS5F%#c}e6>F?Y0tp&503XHtsWN9K&;N`sm_0BL4wKS5ks;h*G z+>-^PL^0O{?!nI-fKRWfsBUmAWszSJ^RY$-2dU?;N|~EUS&=b{FotGjF-#czz<@~T zYS-I?d5;Wsk$&^#SOlAqagL>kAm{7HUU|%o2opy%6C=wcZ6(8?D%(dy_Vp*!dR5~b zsKxDIf;P2KWJqHnWC!?|5=P;`3Ux*okg*=P{+;_?E z^r(u=si?o%#k-{HlR+)$cHDEyoRZkbRp4=+wA*P_@pm~Z9FUPJ5rClco_Pd%`=45X z#XR0@w(`Vf6E;?8LlX`&g(r}52P5fLbMnY+ay7imZ6sl$XI0p8%ven)h z!IDId&hoZQo%;39daSE$%$J15w*FhqY_GOS2JB%@2nPh5w;#yDvdsSgEE3Q5F+S;I zX8{=FgO20^Mt#jhw<%cg0k;yJ?{ymL@b-@&j=v zJxJ`pX8_}=^%aYZl#ZBCNfHYPCzsA^xh;U0#s`>0dG)~0=|;&Oc`jpKu3NepVf zUkfSRfyNfW-8JlbZm&*2Wijn=eXeFkliZ8$StM^3=D*2LZ7?G1b?4Or0m4w z7(`oibhf)`R7e)_ncc}C#&eIRJ!(?V=P+m_gKB>4$e^y%$i_~1@vWz2DgGp)-#Ok zA;3GAp(BifLB&IA?;NQ#R}C7@7$e3=lLUO+=b;A}^!nDE((DRNmQ~*ZNWavQ zXf4@eAP?SmIa~~%UwVQ@`&=;ru%*HeElUN$CV zFBlz%Kgy$2U0RTnB8{$~`Jxu?fuHGDc5cKdn29nU`*4i8jX9 zmbYdm23w0ID;l?SA%G#20ad|o zmGE}9-sYg4g{{@V6ER7Og^hsPqa6Sqq-XJ}P`WEs5>RdJmRRD#=0IjryLS)bB=+EO zQ3z*C*uz67*)DdoT|O06Pa`=wBj^umo=wp!migI=@&P$x+wiEC;vX|){$fiss;vjw zH%BJil`5SwGRGsa_N!_r(^JYO7Yl76XC+}g$qHeJ$3i=ta7{@9{^dxwFqL&!gKZ}R zr`;rDuTN^5d_q--F+`Py`K2VO>645c_o~vw8byNESD9iYtc3t>51<(4ywwvSi*jbT zPcljn0La`$%+!46+$5Ydqtm)-kndBe6 zi4~Oq3mbET)3_b#4h zAoG>RIp=|n*cB5j7Q4#^LhA(~}O3}p2@oObGZR9CYhRk*XY!tV=*JGQReXBY&0-Hv*X zdZ3pUw^qPTu&kElxBZ?%&$}lX&N1m%6GweO`w3>?j^7= z2+sCNg}|JM(BLZfxta8kJGJK zOUNzMEQH&(S7H0W`jUUoT9)N~jUT%a?=`AUB=auP`ZB&>*>A$Y$~tb00yhtvl6(7R zsN6hlJn~NZn_sMDt!IZ)Wmx26hBB`{VwEg5o`i$j6`(C(Q6u>l=%s3aY~tQY*ViI3pYklaYh;?M$9M z_c0k3NF|z9TbP>)%H4}~{_Z%>LspBYRw-&v6bBC|^QV(mV> zLhz_bB!WotH*8S9#mEHY4{lF!)}@MejmcD#&1u>>8DStO#(MNUx_&g~vyx`}NRf&N z%UsCF8H$cF*ucp@&)%KRnAEu%2x4?t+CXE@RhaDn=NxAkKBxLssF2DoBbM4o*&`U8 zz}!^lrqXeq4?fkGB+s@>Q10;(UO3kv3=DD5X0(L!mX<3Bs8dUMI2>tlFC1M%QC4X zWcSDT)tSUFG&YwgBzKW_Dn8a_9FT{ed*>g@mo4@QLc?W<{gvW`0IdPbf>ehmufHEo zl}w|^n}PZEFx#EEVb31*p#Xi$9DvA~RfaxW)Z(L>IU+;l#kFS<>Cq?q){82hc`e$8T(|$a?2w0 zR@=Z+lY&QFimiUK#cvx+BrhUeD>RZyN|pXIo_QUr_0N|Dz1c{9(=73?AZHlPe++uo z6$c2arP8D|^U&zI(qD)h+!e7`etewp@#t^Uz*GVj}&cOYULfyYeo)BNV7 zGF)4?kt#_XvkamF6tbR}?m--nZfj_}NF?rw1HmfCZfChyW>%03akW)XKyq`QJ?N6^ z_U$d>XsuD2`M%9_6|jYvDCJo6V}Z_j`g2h+XG#A6aV@07_i?;=A!gv56OF(R^VY3_ zEyUt!uO98vRr4+;C7FrpdFMX$(wLQ(Lgb<_v8qEmq`Q2`-cu&oFf+G~RFFs=x^q>5 zT}52UG#2j^qkY}t`H`xguG?}*7|Foz?Mkoq)G%8VXyn|?h})T8r_JcV=Y#3*QOyK; zMWm8H+oMJco6DO*(6pX|X)M8VrMMW+<54u)Ixhzj>cuX|TM_>1bL6~9n8_bg$j4(q zWR_`=7e#h$s_ZgG2JUgtoZxzW4OTbbX)#X~ui4SjneCw^)mzYH=N-A{`P6X!_F};q za)p3mK~bKAuNbV<>~qN%E!|k5BVv_h61EjcQ~2^Z`qXjH7;iFWR#_nVmO=N1Pb7Nr z(ycTtGJ|kdC}SJ&SSSmO++I7{70=lU>{jxs<6urdZu@&m1BDMyrvMY37MY|^VQ5CZL@XQ2BWWoS(UU zq-{Na&TAy@X-<=|LAZNyCG@b9D@K-{K`AohI0yJ#bEvg-w_hxnJh0NhvISCC zI5^;E->)?t#KuoLXqRM?zwa_K3woc!`3farb2JWsDtSz-%Glga2qWr@p>%C-On2)7ZbdlB6mUr9o z2$uw~KD{~P^{Y`NuW0iOyyyy+iO-jToDHXq!#F3tJ*s&UiLEH6O7d=nlr)jY=KSS( z2OTr?=O0r}%Enlu%uuEQ18HH~j&Vi2-eeNnlyosntsYL`{B!*JQzY|bat6Nk#@(nZ!+Kj#0;Ed z0nQH`o`aLtX|37_7I&RucU`R;425ENKEH^nw@I}Lk{M%pKx7SxF^}T;dlEMR*9239 zlImj`mV1)0k=)5|1osMw`^Ak$RegCQj)Ok+JkJ=DWNQN;3QfF4j9}xH$-y9W{3#&W znASODSfvLtNfA~mdS!ci)kjEE?CTRbl+5ig44^cBTpS$w`ikjN_fE*)n&hhHNgYB6 zf^H>83a!o+dC34{lic^kG+cRbd5sbuImB`9K+U-P#4i~K<;f$kJ&C14jkYNw$=b}) z41mMaJRH>a+J)3JOC`Oyuo9P3Z48V+k0f9cNx>ecI6TyAVM(KQC`}!YxS)q#G zeak?NXn}suB%~iQO!5E+JC}o!0OWI;g*$G=7_MvBedO^=1+u^H-CctXq!W+-09{mA^lMK=v8xrL%7W?0N{vu7qX&Q9b~yNST(j-suLi`CiZ zr0_eP%M`$89f<3YMcC@&Wx7^)aJ>n0vTuPgrX2~b!&pGaT^{SUK znB)c{6NqJ9(YphKo(?(BPtUJfQM-D|Z7(9R^HoHyM%kEs;G|^aWN=3thgw-glTA59 zA0%oZ#2Xkd0AzJ19Fl0hq&O?;$!-hV!7GMWONiDmOlrjQxZ{ke$m%;1IulXJYjmXt znP(NSi*X-k4I?)k`J9p4f&FPFo+73dwoS{O(vW<>+=2%j?m=MSrb^s_kW`*V2U0PfeR!(v zwV4(I3L?n2W!q})B!F|*a2dzepD&p=&~NS$nIO#41{+S&OnEp2}&Pt5)`0?lo1WQiGAFwXGdSmW!~w5=1%wz!fff_0M(0Du#>jO{zI$UGk2 znXY<`rYeo7m6j8-X(fLuc~I`b8Cb#oyi;PhvAL2`&UD@XxkI$TYQx*RJc$*$l?CQ@F$+vd|4a2y>J%6P*Nx2aiyKY#;w0qv} z;Fnx{q0joxqXWN8{uP^i=2#wBUTFii>wzR{JhR&bbsaf8@_hw9;>}}d9bk58Wg0fAvN<1lhy-n^BCrPozx1g{OUIeF#?iVn zEcW0tGY&TLM?=B-8rBoLF!pbI5?wUT=_IknN-$3-kWN1j&Z`^7ju}jwt)`mbc?%FO z_&o_6cjAdHR@}6<(ac)e7D*6G`?1agGW0#hO2_<-jaBoN=0L z>uk=+4ADf;kCsVQjB%fEFmOEuSxJ7&9L6W|ppy+EGYlM`zE9$D^{xx*Q>z;kn&?S1 z)5fwH7BaHr9jwEt`qUb0#Wb?~mu6W3UF(w`;l@cL0D^Ikucc_DCfj04jw4A~x3Z5h zw+;``k_hSm`qgP#?VdYzyt#PO?%TO58lUz@N~l@L6-bS^iu4I%^VE}-L6D)naC?14 zHrURFM4mK)Qop}+#G#ub7$kK##z$dR9tlP4DzS@;H-%062|Tt3Jgj^kaoppdT9hG{ zH;M#}7AytdC{jl~0p#P`+MM)}cO{;7E14BUQw2m_q#XDE06x`S?XBmGZWh~ZrdGG! zgvinZ(GNkM4?dk~?DJ$HPdm%p%jO<4(?42_Ci}ljR%s?m1z=K_b^j|)3-h8u|S_@n%!0a)<7x0VLI)3GzjOTzkIOd?5Iix8is_hX-Sm2dkFR;Za zB!=YK1)5#k21&g03!(cXTm@AeaHu-qbvgd`-O{Y2>?%tu4pif(By|-s!7ST$F$0_^84SL^ zopd&O9JlfYxoc}=WnB3Ym5wkE9;YJ%o}}~FG&|V1v~$MQt{z5>t|E?TaOl`FDFZxk zHs!O^kTdw-OJ&-D*z8EsMIsU#Bmz|AXSN7EImcS{7_@6^W_fmpS&?_nkd`cZbR7C} zYOU^x6~x(z9d^K2ouNZ>!997$82UFf~tepC$AMPjfa}U&wYxow|3L{Doi~+#Tf6i*X=4MU#l0gnL6lz(QJadlO_2Pw9q$uoDEV93s5zLt^o@B-_ zpm2K}^&~0ke+uetqs6@l+z>(OD5%nD_khhErh{*w*o;=(PVEX#kOJRP} z8;}jY<0%ocwnH#I{l`puR>|BXn=9TcN5T2f#@{~#?(9AOwUDz2 z57M=@02!i*#!S13Sja1odsa-=K64~{8C4ljICH~yVqsu>5jktuJx6sLm7+A3b8RHJETN14vm}TWokZQb<3a6`>#97yu5y zR?%wWM3mBfm|)YhO$Q+5NEz>s&Z)}CVs1i47-zOWTA_AAMYRzWAQ%|nFKmDHsFFqb zm@4m%GqITb!2bZd{(Dtxh7zI#kz`(_vN81hE0$Ao997w8PUbd!$k}`kFFbo6aCkW4 zv`43>y=2B^S5OEL$A(lwbGyDydSkU-hIrmR-!lBihx^@Vr#)56oL$Q_hbO*0>1eLY zT^WTGQ%iigToQioHItHx0y#z%m^(&)ynqw@jaMozHXYId0r`gVp^iG7b;qYq(yRu{ zo!J3E#yV&G;+q*RS+UE^D$Y3&7IL=45=q zKqO#e)BI~);#nR!3(6W6$_VCVQ^)ZDaNYXXI3!VU&m_^r%tFRxZM&bYdHdXUUVkdl zOZ8wCTg-ebIxpS}oM+oTD_T?1$3lZEOv5 zqXqu}b$}ze=h~#+WRJ{eF^@Cmc)-XbxAd&bhjp2<7|AaEj^`gJ83XI>-|?+xlSL?4 zn)%?|vN~=H9^Wwnwnp#Fayj;@FkeDmMNP0a=2dqYRrl$i%BjwYC9KZ}+G3pl0Ir#1 z$IZt>&T+<0IQ%O*8>p>j!FKc40khS(Jl8a|nWSuWQo4X$*t&>_B$4wG$Dkbl0F82! z$kM#V*;+N&xGBo89Y;!WzBh1SyoPeDgLX>p1pXQNVzMu$y0&YJn>ky}^8WzT#f3Yu zgMu;F-`_P#?d(2PCUww=1TYz7f+-{)zA`XX86C;%>BTZjS))}h7$_eu^ZX?BAED2s zbDCzSG|D8rE0W9QJ;o$Mj-%$z2sq>XE3|@0Oe6)7$yR0!Fm@!KfD@7QJaREvrsQE# zJd&}?+}o76NgolI*b)*vgXl5O=l(RZ%*vraPnJ#DSn^LJuLnIkAAeI@w^qVTwo4RM z*qF%1YoEH3c#AZ4a1~h__d$y72LQJ0^NyesjE{3r)tQ~sGj6==Ng1RbTvsu-ow+bd zo|rvH9qT{Lmhwb{%Q75(>Nr7WCmeCq{{Z#s&D+l#FP40g<8;1oF6J}P0x|}24t+kg znW#Y%N@R*cq?W``$jZpQcq5!2uWox#thFvMx+S>#G~gr_mr!|j;hJ%F0{MeGx?tnj z{$`c1)|RT%hA_t45Q11M9G};(Z0~Xc&hd%*qn;5kNjkU-Blp^{s+oW;GGEIRE>00F=xf1aYEorG-L;hHdiOpN}7%cx}$9a)uVRl!leE+Z<$};ekBxM;Q0_u9ryEC5@$jv(8#Lnn!rq zSz`l@?axEN{6%LOYG#$Xo||rko!LSr#%+wimMVIWZsQfr>Sji`F~tKoh_9Q;j57BC z`hoa(mn{m=&Cy89&&pecd9p9#kJ6i9l^ZbK~aWP_4?OByRfG{ zNv;|cSy5tS+T(_ZmCvu?&*fNm7iLKea70<1!mCCyNgXlx`g>7%sF!sSIR&FCK_n>| z!OlM#L0DzxHH;0arvs-LJ*#xwVu(^q>@Kxyh<2;n%jAevWDg){w1hWF31r1tRhx+C+1`RJ!_l1(PwFv5e#2riam1YO?=GOVB6b9cKOn%+azFT0|xz}VQqS}$tr&^y==P!vm zHk+dOdrgou0~FNoPT3q5_~Ih;@tyL(IAoHdyUF29G`3&_VDOEwvmcN~cgOZ_})2~tJyKa5c z@O#EK5Af&1*S6|loiuB5w)5LGdz6LU)MPLO9(@SSdsMz6OZ!E;jzo$ZWQ++Vm<_$$ zj)xiN0CD{I4+8ug)Vw#R*m!p429`T3XyK0LdD-MpINCdHB$9FHF~)1%ZT=M*qgdfc zp?KpeBny?#9r4ru0IgmQUrwbAEMqOv+m5X9c$ZSzJ&q>VS-lMf(Uqf+vapN-%+Zo? zPo{nQes$PGud_oimE;#oFx?Bpe6~_LhUna5r{`O@9|(0jXzlIo?%`Hw3rg~2sFSj& z?mOh;8K`=1ca9M9T5a=M1|?K<>yDn8uUZpH?s7R%iuaB~T9)5amI+V@p@Bv% z*p>>%sppo!_=MfgKN!&gVrbWcc|%iminE1H7uuGdr4xq0Ta>5(UY~_^XeR%7SPL=aMt0$SYMT6Vw z(p<69BrM9x`M?aB!z&JUp7=T9s~3iq346!(cMow2%`*5@Poh0z!rnjA^u12TUn>6q zP)oVImnB3pdgYP1P)}TR`WpKm!&;`1u4(ts2*g&`P?;JFiGWi&at7=UbB;ah^IyYS z?e>GJ+3P7Kwa%$#O~SPHG2TM17=ykk11n(TDBy$KV!iL--;Qr1uv-n%YInCc&esf) zD$8=kvWXHd6<;T@$3QV&CMr$YM`Ncy%j)L2e4}>1CVg{f@fIHnUbU1q$gxQl5m8F8 zIKj&<4i5v@o-0RQF?>kTwGArimff`xAD3+!7L9T;L1sISF@QPFNyx`MZMD2!Drda% zV@8G74JZYP13QmVoad*dblPN*Xt(gINY^vVw<(+}DrXqy8SBr#wRhlZ(xYi4)VtjN zb>dDJ%i%}drqxcT^Tqpde#4rF!)flkVc~r;?&C+io=3RSt>OW#_maWap)2o`kAAiI z<*jK#+Tn%F8=BaSz^Tf$e{`NN@U^eRT{h!Q)h+EV1op2S5fo;Q7;;X<&Q1nT;&ax& z0Y7Sw_$N-O;A=g9#-10pH`-aA>Soj7U9B3a-GRvmJb(r|SJWz)9DOUwO;!B=0N|gH zRLijx>+&e=*5~30nPs?^+$dHG7Dgy?7wcD~OKW)imT*LAmP`S+kCfL_t7s;|`d>L( z+Th9M%M+&3r?|(cu3kX`KE>M1U2^T;+PrF%(vhq%{Hs$YR9RJ~g-@EW?RIavSJtar z;@UXYL@zLrRP7_>ZopQ{SX+5w099pan2{UdmOt<{O$EQ1bVLfv35=uphj#AVes#w; zsZxrJips-tMrK$c+`)IQ6a(w@sV23I!4lh+JD(D5P}uZur9I0D%gY#*3a-@)@{jSN z-q}$iNgc-N8+O*m`52-V7S}l{M#Of}O>qMw5eu!ttABWr@9sFJPi~RS(Lgq&e|zRX zDeG2E++hShLYGM-%!&?J_RrHFtwk25_HT3&1d==5zH-YLW*qbcgM-_Sed~Mcp^RqY z*&1z*WND*lvZ11KN6nr(`_f$bVmM9OI7li(0(~TCub>r}>mlFBXMJ8luo-y;LNoLJeZ9OBL5i@yVRh67_eFxUJS`yP&CW)FjTF=Ur zLzQ`&Oc?ieKDi&(rImb`=eb$DnH`Gn-MBX%m0Ql1PcfcHwn$lbqORs(0ng`FVi1*t zu_h@QnN^f-41c9(Dou*bky#>ni**;8-~$&~fHO+ivEG)u(d|W8^(X zGyXMYE*f#MRZ>Hd9c4z>1^`2|Y#1>nLlw#5u2@gHY%&CltYM>JlBe3XvWcaoaV|`) za)v?YTgamz;05iGOBKA(W(#{*F(jFid;nRGPM@7zxF0V82vV_y01&I~?OwI;>*1$} zylbl3>AD`AZ_CJrSYzDIxy}ex1nuDS&|<0LBNcXG?5ECU_!Gc-w}`Kxf;2Z0$#4XA zn@MIM6Ytj@J*)Z;{fYG3e}oz>wVl?6yCk(%yj$gw--+@-8i}$5vW9TxB4lZ>)+gtHIgwd{|)bw+6YZa1RT50gj1;mn+V(dU@ zP~)*6o!B2J!R&A~ok=azH$`_sttHbj-0dcM=clJXO6Q}wheOh0h|MBM5j@C>x6I3o z`(W3bc#p&>b#rm$M$?<6K@J13je1~XkEuV>y4E5Qr{;dE!~8c^t#v6!LM?XTE-!87 zi8q;Dy!lAl6y)G{&lSi`c-D^4+%w$yljhcG=R%OEaHu zDz?Tg(n2r~80lFLVK5fKTkRK4q!*F*GO@;69AqAN9@XPlZgmgXu=sUKl8G*n_$%WM0EnM7=>{m=(YpIn;Lw7VDf)^@gvf3#Lm(#(#2@Am-p>`#1*bmuNx2X~ZP zZk{%bd2)gB#`)^Ql6qqUo<}$ay@%jWfpw1(Yl8IYQ%;X~6u28>+KtJ>a5C8$6^!F3 z!{JCM@4JTj=Z zw-JU}BW|o%jHyxp0AvtOPC%-|(tNjTMt?7HHgdCU%5^-<`_2Ab=p=WNDL@yJ0?x~f z;BW>BKd08I+cllM*85b%%8TXa1ToLI`Nz_oGe{w8dD7wLjs|G$ZKD!2gddd@4nAT> zK7`|*E1i<&X)X~XSy;QQvRV`>(Wm!D;h)8UjqIwi}g* z0k^g?R{&v7K<5LKPmP%d)?^iIw7-D}|HofCg3y zGFJy6spxV(hP@WaZFLK1;L_%bCv4(Nt8($i-s{zramV3V&Dc;}k}wj=3rkp}P_g;5 zvPRE=yB|#baay(-%N(l1S(cZWF{sGTWa;>b;fxA06bi6x;m`o1F>tNr9!=Wd? z2ON6Wnd{mkw22JcU0dj zK~a@QBsW9GIrllOdrO#Oo?9rUp4_C(BZ%YX7HkZwb!8(RdR8^VTEldxB#5Q8xJ6|n z0O#gkZNn7NGGTV^v)@zbD8_h*J9h}d9GUF{?OT)WgcXl zq}xhHa$9?w=D2l4g%rlfN~;fJ$UGjRoa~XRi)i&bKeKtU%5D6RiyxehN0`cZ4aXr{ z83c|7Gt#oPy)m^pU5u!v%6~3M;+Q;TyO84{ha52CxRlnWg5W$iGkG_qRQZ#c7%Lum z!60Ou05}*OtESLyzI&I3R_R zG7bXZj4(LKIUPnac+9%f?hUMKb7eK0zF`WtKr;pGcqfC`uW^to*)8MKk_47ZND^RF zA(2kyQ`~)e;E!s_)O6Ucp}A;dx44l=SCQ|w7-Y{FP!9Df8;&{0KDQ^Kmoi6>wUXaJ z1hW@{8KZgH?ZYzTKRaL!Gm<#q8rQSak)umV8as;vbXw`7lgp6Dft6B5M@|U`2Rw6A z>pCp@1P1!X=IJAvbp|UIA%O%OAC!!B`g78`TQ3oPqV7n{Q<+`W=ayCqtu}c%IW5P3 zT>4UtyB5;!YU>&#cClOimMJEYasiS;-!IhH3N>l0^(d_M3n+s{az4p$fsBh8>M`hj z2t6}irG0j@O9c5Ss1;(0B3d=w$sF^+W z!sPTHN~Yr$R9m-mzqPze`)Bh3dpDRV1eB6anFE7^x7Vlh=kL5Nd7GEC5#UJ67st*E4zWDtSQMNhGR~h`{PcQh4pxpaj=5FNKYp7SrRAW1W@S-Y{ceSp1C2 zdCuN4dGE$?So<`d#xsvJ(bFcUmQ=PSoGO)#SbU>Aj(c{l*G-8vWm4`Otg5CY8Ex1k zW7qJnBAVG_l0Ak! zjJzLns#wcyrrs-kpti!Koy;+x%bqLcpA&cj?@Cy~5*Q$nln93h)C0F1amQ@*=Dw!V zd_reu^Cpb!45|p)#j)F`uWw3zvewhumzF55CXxvXtco^)!3RFRpGw|t4lc-5AmH~t zKhUR_MqrSt`4il?m@Xj_bw4*Jk%Q^|E8SzAub{Ayrs&q)RyRgD3OUFAJy=?=h2zyS z={z=o$kIs!agfXaKYdBzy9#!2evX!_~&Hzl1RPtE%J4SitrKX{IX#s-imNki$mEC{~*S$=X zS5jZJNU1HAm8H0f-p=w1V>11v;h)L4nm%_bNzTSN>Osd9*y-LPVk3$&{$9^5T1j%s zq+pgk`2KZMQMj6IGE;j!q^y!FjgTKPw;po%JdV8Jb*?2OmK{OH0z-8Q`BE&HSld5+ zh7TA7U~`|!wx*>PjFObzr(fcIJ`F(`M4m&(I-j)d`LH?UatI?J_w+U7`rV7gBivh= z46_GVpl}RsNzcpFk_W#`{cF)9)Z`2nW{zZaA24m*J%1{rsKIG<3~z=qNf`?oWEJ4! zj-3AhkEL%?E>Lzir52ImJLL;@>e2nExFH@QNo?{5{{UbA0N3b#6^ih|42wV6UgW%T zO5n1p?(PRX9^Xpo^sf(Tw-F@E5RpZ+pJ|#H!!&Q$w?Gx23!b?ngH$ygD^bx~?N;zR zMv(sLQTDS2>Z2q8PfmTS&2%QGsOwG%cCqYwHT}NH(U}_LM3J#bS8GCZyoTVbWG_M7 zFd_zd8AQ@|UclrMdGz(H>U+tWPIE}+G`&g- z^kX{jD$9xD1NV|1qwAiv)ZA;9@W&hm9mZG=)mRSI1CB`G9{loo_o!v?p@LcAlMzQ4 zSkWz^5vpwi1O@Gb$sI@}l5%T-X|8SV?;?`xbi(O_Sw7`uQTJp#VU@B#Bhcp+&mU@; z#X7T6J!8X~)%xjI(OJ%(SJ~P$YlsAm8V{Rr+zC_1Rl&waa7eA#9d&!O`$?MC##JRH zVi>f6M9_h@Tn#?fC7q&HVI`3}?OwHBQp+`&unN(oZNV2HxShkem*^ z`Tl=e?{uv`&MOIRWBW<9W@zpi14gX9PnP6kBh(X)Ye-O%lI%@adun;TrK@Q%PqNxE z92cz=EgE5_W^NerPXK^%#~kxktx1;gBVh=EBqgMhVH&7aB;z>GOaM8__pQxF&MQSz z8J<}-w%ciECu)L7IXrWcayj+uTxO$faCHR;nG3c=MVK*FAcMFMR^7q>0PEJumn!ob z99`HPU1HKfsg>e>71IG^~=d2aT;3NNgS&hD}v6% z=a4g=G1Pl{*EI&8d1ou#-H{!&*^}&PY(#~m8BhqwEAtE-@&V603YyZ!;!B8{Xp(7` zMs4f&ew-ZRj@2zm4ldR`%fgR-+H>7R%El7Da>}KP9OI8px#zdNdw!jFIkkp4a}h44 zM-6871*8_;43PWvsOM@D9=sAlaARW`kM3|LRlk`qPMr6;#LWP849X0 zGR>bs*ndjsytzEg@d;IuI!lX}Y0sG=k+W=YE?Puv{qv3roZtcd)1K8%duZMZt8sAB zP7#_YZ`IX{7!o0OLJ|2e0E=Sw$Msl1D|S z&!_(YXiE*NTul^mF59V4M$$GhmQYB^0CAEy_O6|ygA%ev=Vu0yXAPps<%wA@ARrtTU|*kaYYhGac+e9vH;QJuS1N3>E5(% ztyISxt2A+}nBF#p0eQ(Ix6+bMCq+7!HzT}d`!YH|m-3U(%Osif^#l3Rqr}(p+_D%V z61LlTT)LI(-=4YSn#osq0TZ(@$=Y_3RC@kKu2_qEb1brNon}Q~CHX)Hzp))^nz^&H ziF3_AYL%n6kVhgn?_JmAJ#&t@`gF*z6Zo%l1R@KGE*dzMS!0efxPkt-qAB@_ylv6ZMB=0h1twb=Z0!Dh|fInLEGm4(i1ljf+ z35Sj+K7vb9kB59yBo{Cy!9PnCNM$$&o$lIEE z%bmpXa&mF)(01a!AJFvMyMbq`O{m3gw}FCb(jjYwW#ki&lmpHIIpFppzK!sfld3d= zS8$nS@?=j=px5V_UUP_!E0#Ua(|G4A%OOHizr2sFG`vKBJBMxTBqVOi{yh$R`c$&0 zQ#!-BJl&vga7yvW7z2WGdHnHM`eM%=lwN1wW)0@A-P_+M>)N-amV0Pq*$8(sfwW+- z9eB_A>tCqRpEV@U=V|jgtcuklSABTRv^TXxA+3)yxLCZ!k%hgg z1@q)_v}6qD=m+`ct0ZFTP`3M?MnCANj6=vsJYzT{gV6d4z96)n;36E6w0WwVnSZ=G z>f=$O_CJ!Ra=4M4*yO;pPFb5rf zEc@1s3T0Jff!W}JeCJ+rdSw3qp7ld>B$Gz6gA%f+jZl(X*F6a2ezh&RNOw7sL~@Pg z9p#4NN&LB}XwG&;(B4=!*2(4G$Vrmni1P8+ZQ$f!l5@^SaB3upo@<+Ro6IVT(iMQ= zA{Hm;uE-s8=B#BFt9Dwk=W9IJ5?aw^Z zjqVCju_Vyjp-G{VS&>i8xdO3peKK+}#(1iZtC<=<-G+VYxF-WOYAJ+P@~Lb-RC%C{ z!Fk97(Dy%2T6{uAidT-|nLOq4r(_CNJpIga06qSvo|UbOQn>?&BP@%kSx<21azkol zQIGE7fFzFjJ*m)b6Cm9Z5*T5#^Bf)rzB&9UCAhnY-9rRWOt43~a*!i44D?rS7blG5 zb;o*rq*keP(?({_SI+Y$X%sJF2Svd>y+@@>O`^FZ-o#2K-?W)FmL5{D0}JW&??f}D zywa$GJBf2P>R`(;#Pxw4ye+5~~*f07xvPk%f$BBk7)b%||>iLS&ic zL*`nRTb-eTlgSx8jCVAmnKol>qmoBhLOhZ_;-OTr&w8a4%^u&8ByT+6I&qGJ9^*Om zr?8MHDt>Zst&_^)l*ZmzcM71E+w%QM#~r%& zsZGSuG)Z#-x-BGc9C69z$VYGq;1izU;{vl@;h>BY8oOK_zHw}m{d;%*wW)7x+he)9 zxsC2#VySE8pD|Pn?j-Sp?ay4}zcZ4#(a9TZGFYdL8K(1dGC$0~mB_|<_2g9rQ!r4g zlaqnKJwM5-bIxDPCgWqB!EN%yuwn+)7$9{gJa7*^s<@2IOPM$1L-uWV1zrJvpmZoT1ewU>^!H2;R=RE%VRzL4rh@i>ae| zCY9t;-fhD<+`#&i$>Y|U<%vg_yWA{gPRyJPp5KpJ=aV?9Q%IT#?ba9bj^fb%;3y%K zb|*cF@klj7PLw5uoOiICK3|dC+7XW}pPh4~~)ldR8%N?-y&%_GDgZNo-YnpKS8AMqcT71_n5 zSw%AWQb6TPHaRLzI&|s@{&hTQYXEs8R`Wh>uDIIX*!2he@mI~E5SvC?=%EqZTW_56 zEP_QU2h$&|Y3bIH#OPcD!!v;xU9Hap*N*ixHyh*Iy}!Iwq$IKb0QJ?#h(jp=tgN7> z;5Z+TtwFr1Hi6)ZUGE%B50*UCVs_)#>r7dZL%|Dt@s{H`_0Q*;Q#_9m$Cw>0nOE(JnU=>Gk&dRXACHd;8BT%*v=PR4ViI$66Za&3qYEA#s^*9ll-a zaC63TJ!*-$jh0wmL~uz(a0vMc&mU8h_|uYcV~kpT2AN{EA~0l=2Wyc#NJo})cI zzLh#k_Uj=MG?4~nwsyzO-=|Fb1N`cX+WAnHSoWe!sS%B`5xRoIuHM)kG7n=~GO;MY z!{$US_kQmfjQ;?5oM+qetofb7q?AaaY1u(`!?G-bE!o<85-RfDyCTTQrCpnQsOm=@ z2lc9=O_9dx%E~|tm^llMznv|l&^%4#$+)u=kyH`^$JQ`7@HCNJBtqpQ1`jeq941E7+@D|mwM;h{ ztkESVGxG)y23?#G4;6D@gBM7H4WX6*D*mXBZ*rs*$5lVU^h2# zNa@cVKdnrv#bnw)a)ErpNDNf}0C&H)w@RMgBq));CI0~Bqhs#kv=-SA9jYe8Wmj%9 z&VB1hBn}WpNVJ4UD#;nS3>%XBTz|U5kH_g!#R9~v&P;7A#oK@h$m8q46pI|GFofhQ zp1Y0#{{ZVy&fpdj{cD`N)OX$Nk7Bt8 zDhC0nIVNP{T4_Xz#Igwh`h3IF`PPk<^bvV#&F4NocnJWa_B@U=&*W>5nr5CT9ek@> zhMBi*&KUZiegOQdatVx0DM{jvc0kFx6=m8xoP&UI+n&7C+QzVhI;i9_p;07eUA@R% zzTJPx=~W?;DHyEeI6}(%R3DrF0M}f@UUKa`iMYtPWgC>>{{T;K=}@)KCfw4;8XAl&;Oqo4a+D?a_7s(y!VCOjVT>bY8y+v`(# zEEmd@sv}r*=)X9-y^Bq zI*@Vr^%W^J&TSc!BgXP9iiKp}cXkzi-Q3CNkR{wyF*0s!Wao~@sllkGj_HQkhRzDd z&;NR(@n^YP*3G19^?a+UcjDljF2<_ z*S%>oB<9*zVv~eW+hN)QlY`DlJY%T-RE9+ifyb8i_f3MV8FBY{#zQYt&P7ivWvAqE zdX|ZCc#8;Ay<}FjX{P|;dd|?IluvjUOmC;E6T;; zRN511bUcs69vZd~Lf1k>Q}A!WCM9kR?5hdZ;8=zYdI z``6lf)sx@DEzQm6nuoSIJw=~}*>3}!?!$s+#w0AR_F zUz91%c){(@TKX5nwsK!hBN+LM3P@aTB=#LnJx3hYZMKc6S=-EJmf==%e6bwF1sEqM z`El!CnPWI6G;2$e`W}8QMxxbjd`06w6J2R~)%C1a@T>)k$t}{duHB@ZjDx`KUK!)x z2Y5@z8cEd`?Djh1!z00FWL&b7@)D=!#zDa+zdbAJuZZ3lc{O?UD~KhO+{oW(d64(& zbICrW)^)drtZl6iogJE4OB$rXtkL8Lw$~t$+az|+YFS*W<+9n`bw}rz>J_1ibrSiX z2Y5@v{v^@2#ciVN4wlyvt=^|(zID8DoB&woD!Yye861zTeF5Q3GVb|8YYhZ{XJC;1 zvI8tDAsNpT`2DoffI^e?-)z zNq@8L4Ykm9apZ>c4m0we3bM8vBis?qGCv4uJ_XaX^;=J{#cIIAG?RIfw1&FX-qT?xR*z>Q9H#&Z&rmfDG5tmquotE%{=1G&& z9m(zQUm@w9ExnD6ik6CRwt|46%#i;8AXSO=7_V0G!ro|_f&m@G(O%q5vvclcQc3Pf zz$XA2;Po9-LeQZamZxD9a>EkG6~(QoX;>Bnso?N?kUJ7<^elo^ql4voqB6X%l1kUH z;lCGt5ct2v_buZcBIeWVuq?+=X|*WfxOE>f^3|A@CmBBAbv5E%8`E|F04!Tt-(6p& zz1G|L?mlN-*#(;z<0p~^1$}3&{73NBeg1i9E(ZOnmFc$Ad#qcWi6jf z2MG(fs&=7G+`& zZaU|;wRm5GJTZHvYua|Dsab`N0UYWlwx}u-6K~XOe!)-$4$B8<Yg3Yqtfl{h2p@wpbA4u^Bf(j zG2CaV1B&_rC~a@;g0m&R*^%9Y;Z@Jx@86D{dB<9*puUYQ)UACjj-4&Ua!V!NyDP&C zaj-4sHs70p^8hoGv}3h-s+{?m?MpXRDcVrIy-&{1+ILHRdd%uFY0Pde?4(=yZfsq) zM-VJgBp)g>5;KpODHbNhCdAJx_^kLg6LjcYFZ*nu&&?-B18@H5&tO4^+kjq!T>Pw_Un z9;IZ~GHQ2oEsO^e4j6@H3P~!%<{9T5dEj^cFYxZUt^h3~79=sps^Ec>wBwS2+Q;EaMWe=}a= z@yFplk>bsE=TU=Dyc)Ejc3Vjjw0l$olK%jBws1f``039t@OR;z)rI}!I)%!^E4whd zy4=ed$s3$6C3(&VIO)xLlxs$$S2T4l8Er~+TEDt^zlwGL03PUiO{_YTU0msij8g9J zF0iWunAaG<-IJ5tp1H3%&@Z(;P2!zolJie{ji@d%E&Slaa6&(cLuZrUo(+B3;=d~2 zOS`kyAhx{`A^!kNv$Y6>XOEQRpOo|O&$WE2-Wai(=TOukiRdrKFKaDmraqj z?2w1Mn}Qj@87Jy0O_L{uSBWB-co*bu=j1yPblF^UmTi^I&nuax1FT^?3Xmw(3`WBr2`a zA|O`jmL7x-)zM0&7+po(oj5F^O0O!4a_nns_Es?8MP+HLU%Zyi-)Vvk9i)y4g6@nf z5*5+DT)LCAlhlkJQvL5V)wH?Pp^4+Y)D!_cTeh$Tw~>x)#jMF)v4d`4F5L)9%y zm1Ms22t;Bil8OnI2hZ+xE#6GVb+dJx4t&k<@-I+~`mg(i&4@ zV;kaZ`D)nv-`zcUubnJBQE8}aX2Q)KEwyXG(eWZ=vMpJ!=N{<81gg`Uan8rXvNCTaZL^Ox=lGkjH4`kN&-P8lS)zOt z{*5Y!_>v7j#JZNbYi^ei`D0JF7Y!nu{{VS{s5u;vc;~f!Qz6#;GM6&xsi|sO za+qYAc^tQw9_$BlzbN~|r*n?=^RJ719{w9YZn28;`PM+zlEWcojhOOWlaix23)3WH zrVk}Q#6J+}@?ODkvfVn`=FZYnx6EP4Rn9pCXP!8%Dbby@J1}%{65n5u_Y~eDvhi-A zr|Ejll(+CmRvSo#qC3eU=L)TXyFQ2U?_BqdJ_~qJB$HCGzSOTC&e>!(mp16T7bE+p z3IRXl_4(7nKN7W9ytKL2wA;Jb(6pCO+utNN0Y@Y(j7qM0X1xnq@!p~0G<1SAkWX;F zWQ9n0;lbLt2ORN|bI9VlXkluqv9{i)t4|9RRePtQ_&Zkc_lMprSw(eo8CHdrM+cC5 z^Yk_EdVh)L)GXw=veUM@;lNnS3}=j}9CMxxd{3Ymv{N12fI$RJyGnxQ*s93DZrBlr z&4HY$5)YP{_@!tCXO<3#_ltbo->}6=wj%@R~O9BdF85bUd<=- zB=LWUd|h*KW2oI&>bgC>t>){A88*bxf=4{?4l~bV_*MNU#kz&gsRGF=THE=`mea|S z8P6RCcsc9S71iAMvsLjPnkLnw6Ga`m#~Vp2NUbJ+c&JF^0(0BHsTJAqzoYsp8JQCD4#j6A)Zd1Xx}(Uh2k&E zYOqR@Zf;4(CprAR>(eym(EQITdo;7PmeGFF<`cP_8;1-)>5iD1MvJTa_TywRiEv-x)a0Kb~)z-435ex1LS zc^JA_inr!Es!tOr-(Se={EH=s&tZ9Y`<=|T@9D}q&)^ZZtcm(y>e5bQj@tjT<_`?J?P!O=3j>;i38l*wBAUBs!0r{ zK3ElXagUiu$SQmFt}g!1Qjb);dkcut-bl+s3c%#X+2oU*rA|QFIpFhxE7m`?G-Gdb zZtz;A^{fi56`Lq&Hs=`t?c8yUf-{VgNzF%Qiwrk6ZEt5fOB*S+xn=<~(2b-VuThhZ zIn5lBZJ$Ge&KxQ_ia&YeQft0Cv%IzwK(`h)tAb<9Y}{l3r;vT?yNk!y7B=ih@J*%AY{5pPYC)1<2P?7^Q zmeB6`i5cJySJ%*1Q>Ps+k7?uRV<#BYq@#YT^%VHR<5s(~Xz!ZLvf*L6CO!D%fsxl4 zKj#(e{uI=;8Ft(YXr6mCSGbqT+>A>c76&`9yGJ~972;ZMtEI!6S?ro)6sqkzM)A7i zJPd#cInR7!gVw!k!@ACjR(pZw+DM8^tg>xZj0}N{bsY8Uk?GHsiKWW4N1vLd3NA6H z{eEZN9|^CmE-fX1#j|a@vjkkXnfxQ19i;w4pzMBtwNpK}opg;1g2`GqZSDa9v$qZE zq-0>@s6DITpNAUjMXaRuI<4@U;ZivCX>HmxXvog}%m#8W032f^_OHBb5U!nX6~c&{ z%MCkAkjufq9F961*OQHntz-Cy#e9-j4DHsv)c*hi)E5Z@G!CjDo*=gvh&w18jk)1Y zaq|vwO1H8^7Aazm;7v0$lN)t$f%i$=4j6REscxc<*xMwavb1Vt3&SfgYE%BC-ZnVe9LTyw{f{srfu(?;0;OYiSxhl1(g#&1@w*yu2Kdo^Ucr1KiW{ z>j9Efn&jLc_Jm* zc^!@hcqh_`XwHbFmgaiFI|qr3VmV~_Ufw{(hI^jJwg+#mS-76!67WP4FyO1jv@uod z!Q_s6kEcUVjyX3mv`cR-a-+|>SmZ5?{Hl3ljGPZaP$WB*ZrHSoGIjHnTRG1w)P5qg zzO2Sul;kNGh?%Y;ke#f8AknZq<t7X*};NPa3e0+Wg9Ldgp^laXZN{ zFKr@Vm1Y2A9kMf@{{US+WSv;Mw&-q@?`_9#JxM)sI*P^aa#W`YOU$)zJ3Nt%;0YPG zIhUQJ9OR!~nCG=B1p8JclHywwjIPFVNL=S=&q0z;wt9A_F2r;!6p*WlOhH#@7zC&t zc*#8E^HnZxgi=Qh&YP&(+^lUQUEN5AJBVA9WQ+`sImtYNI$+R~lR2Rls(K8WEyw|h-7jhZF{a9o4*{{T6tZXtCLx}Cphg?z2FAQ?sgD$pfQHI$&-DboUq?{i@xc+e^zmn(<$p&$voDIn(lYHFS%0YKeOA$)A?~RE9OB2%`j%$!(#yOc;Ix$t}4}wAzMi# zDDgtX&2hDnKqENAVDNZ8Zq0+mF&#h*QVAn7~a$6DwX(F+em6wc^48uHh$sV;P+lzRa_L!q- zkJ;47Sat8aB;a=U6|5m7^%cyue2tD4?2B2OyKqMj*M z+V0Bjr&({~6Gmk1<|A;)#&)+DJv&v=dis>o8;C8TSKQKwp$e*h*#m$*KMK#dw+ynj ze3iC8x`tN`B!F>@@H3uy?cSPhnbobMk~vYA_l7qaL*G69zsahMriW5A?XjaO3rPjU zmhb(V9X!e7D-g-xjojdY&QAk1mnglp`%SA_z|JPyaSz)Sf`EFXjvNl4jt&Q{UzUBU z%+L`uQ^suLo)s!%>InxRf-rD+ITcAKg<=UPiSA5|wIona)DLRtIF{s)S_0P9rzNiZ*1DccfHz4jhjT1v>&XWlPg;^&n>%=(JG7agGh^(?MA5V7 z3d3$jGJ5m_lT>ap^0a|~3{Ke9KwmHTefY*Y)IwGhYns*;@BVo~&AgJ6G>!=?C#FB0 zIv65*h#$?5?CA`LWQT5W3CB3W$l!h*O;nEUt(JM!mDi6kik9}t`VM~znmFD#WsTY? zQc2V*Ha=6=kISuexya^myC;@cnq*DaDd(0lw6BQA92|Ayo_Xu_s*i0Xw-78LUQzPI z<&Fp^{P9v=O(c%r+=f7a<2fH*hd$L#RcoBDl<5LHJdxUxn^2HG_{kXH44&qt-I~Ja zsPHtGGDK%H7}1t|F$$6P3Fj=q{lic7AzLhM@ z-de_HfJHoi>56UlNE@izCk1GfU>=;F^&D~BG?PQ*z>zLi3#i$c$lPZmpuqI)?rLRg z5i2A>_jXq?GXpeNt8mJew)U)Tnm&vE_SqT8AEm)6YticO2$fU zOJP{5KbdXv)xkOpeZs1|EEP5zZ<8CCN&3#`o?NKYnYP*`o}BOKs; zY9woT-D7KIid0?OhypeTjFIXv4i8?nCDdXvB87tHLAlj1*dQLKs^g9`*VdbtF{eG* zW_V>cEgW}t>|K=%@BpgH4nY9@(0#eZJT#Gc>e2~O(SF$!OjmOPd!D=#gNn^4pJZlL4+-{(=uJ-CHdI3^N_7|CQcCv)Th1}72bi#BQJfKZ;)4Z`3jED|Mc;guiGIDtxa0eXHOH&GpqeY37d45&A&2K7j3n7vWww1!A)Y09BX`@MYsAcKbBfr%1 zTLw+G5{8guWr^mMBZTujMMj@&HH#h281v#b?7bvD?k&Lm8iPtf`V!Pg8@Ad-Gh~MRZz@&PKPA z=t_WwW3iMs9OMJ_AI_|#t9aJaF8gx?K~mdto;e2?>5?<})E5^v^CCu6N9CgxWdWIg z{dEe-EDIIGB9j#BkC1b~^%x_k>+f1Nq1MIXN@iLB$h!Y)?bxQIuEboPo3_knrlUhIbpb6 zsOcxnSP*fHdU_gly1@QaOA5slXcjoFlq_RzKs!L}IL}^v=$w?E#x+|?)+?o(s@oFs zGtTK6!i-5Q-GJ-XuH1><-K4llGP1J7!ZI_cLrG`k~%efH-wva{{Rr_vJki(vb zk5O84wBiR7PSVU!D^DD1*=+S8KpdY=Jvgd1@w95&)S@N2n4I#&_ZdC^0Q&WDx7)!o zu@Xrmua;s{w`m-co_7wO{PRUgshT>IiJom?CKyOLX_{NFEQNLl0Q}uSz!=Y^TsHBs zNZek2@=`3m$!sQ)NjnUCk}`W|J?YCN4!^k~2e^3FN#u<2>QBl~6NJ2>{B>(|2^D|W&Arx(KB%$VX3eqGY`byIM64KGcDO{{RtV#y+_IRV*<^u4TE9nAnw-Eu?7VDlyTqfKN=(smVFsOk_rT zcavqS#FENdRFT8BPdl^FgT^u26tcn_$(kt|7x{{`5-24@5JBsV;EZr^cBxy!=W9|mkdz3A) zz&nvfw%w7d{xMN$rLowS^oe6q~QVe%I-D>68(;E@n4drC`-a~TDc4yvRa07wV$6qhmyr)Z72xtv4;Jc9>5 zx$e~WirqroO(RG4c+sU~C8G`NfIEFV)bh%Sbt{kr8y9rVkU-?;+v`;ttC?t3CGQNk zh@!@b?8~t7@tx(5LAUx+z|f0yk~t-H`HbIaj43Ccct4N-0II6qONj}UcEk3F*)f*g zj1YTZgU^4~pA;^(Z}vvHN!j-k5guU~=rhJoL7!^ZVxG9^WpDcNSV!DeN~RDq6%Jw|=$u|*S!B!+ozA&w?%nWas#Dt~>#oGB;M zx#Ql@BGp#rBB7;=YPjUIWMi)#M-_~t1-X^s2G}eLsIoWjvmnfAl^aiTcp#3PRF`;; z5cYQ7T+1)d``}|Lae%9h*%&;MbCKVy22%1EP~iEae{cpm4&3#ngoO`oh~sG?<&}e} zJB~u0qXd6J-mr0}Z5hovw``d%;SPku<|~utZ~+aT{b^V{qXsaf%EYGq$_G)`9=OFh zEuw-LEu*x$7cV56?w)XCn{nY)K*(jm$tMIb$3sxgOm{K7im^hdrfCS{IX^Myx5_y5 z9<`cwWJU8bH}eF>IUYrRb{Mj$$>Tipine~z%32lxw&>8Q2Xvf_b?50xEMn)+w~iC$ zUBng%no>5&>JJ~Mw=^4hVM$6!8#GQ9dsmZeWRuGSjl`(Q9gc8uniFZ8x=srB6UvrI zA-E8Q1=%H$TOn9_dW`Yc)7FG}3%q+n`E9mGkdUg!oUiwXPDgsM8C@cec~w+60f-xU zIrcwFs#knFi^l$7k#kY>|N)tNCCiH^!upPdxs# z*{rt5Zxmiy+S|yxhVPij8!1Vrf^p^6{)EK8JDFiHOAy&>mFI-V`vKniB2$RUP zP4SJPRs=GiQ<1?RPwQ6~b1LpcQ9*FhlMdB{F6nk-YXsE!# zY+3FcN4F+Ph!OzZfzKEx877-7D1u3nMnejGi5VeEfrFek(~p0pXH1bg5h*wuWRXDm zNgtPSR^xM%nVOz)Xh~SiYOxhyxyznTc|V67a4J}2P$iAZlFGk$Was?xPJx<4wwX$0 zV;R}=1tbiPgX#EGalq2gzjhUT&zXoI@}n$A0A!5x zs1>gvZ#L>XsA4DOw2@Z~$D`*Y^y%zs#F2>>;iVhSOGUH-az4EX{*?+P+hJ$AhiOJ; zNumXqb_hVgJ@eNeT24t7?B`(+$suS}khGEoL`DIQ?0|9C@u-prwmqxFE>Rq8GRh`U z!16&IgK|3K@TG`aHSzl;ymo19fn@Tn*<(BdfLpFJjE*=os{n@Da)_Q#xY{F*P_MM| zc8(9PBc~kmRePMyGh#&yu$YqNgG>9&2&W7b4mm58!OlQD`i?6}!Hy{5ZL-`mg#sqs z&raMNoN_9>t0eKtk*p9$wD~(B0z$`vS%)kz1_9~Mtw^ZR`F>ir$q-dn;D#Mec;NOG zoTA%1DI}6JCK4jY4(O$t8MfUl%&u8MK}k(JlsbT??{k(tPyYZ~vTd14DlbAZXNF~lH;qwL{Hc~)bUghHJ`llf5Nvqa z!^4mRD8>&x$Fcsk1+!d1G>YHpODt^A#TtcdsN`gvWcJNyi)V%7SDSpIBGXBYs;YSl zgN{c+dy&O&7jp|V$XP8HYRI#yNuA6a%q=EB0~qPl^{pF~w~hwbk0vwzxz9Wio(^;0 znxVN8;iQO`5|$m}V%Vr{951W_v~ z5(X_3d4+yeQRq4A@9kOwK{U5JE@X*TAd-1RD>g^!2*@OR)Hc@JV~#9uXIAq8eZzK0 zz&Yf7ar$PWc%_XV2=aw;H@^+EfAy$~QU@y+(qO`6crE8uK*{GFtGk|fAd))c*A)z= z7?MLgHxfLE8r7|)*r9;Q+z2~{0T|<+{8c8kYq()aVS+-SVQ!GJtMyj{gOzMBKE01h z(@CWJC9>@-(F`)m6#T;=p5q6vvy^S%AROqj4jlb(H34?f=M_B z<{dHlo@{>V+D1r}M{cXSCnOESzpwc;*exTDGJMGal?RyyP>;4rlPKQ#8QrNZSOtQK#NY~|D@7;iV;AD}EazDbVW6E29Izel4SpA|Iq1+^o z(HpTmFej)4ccyu*70RDH##oOlY=Kw-)c*iJDfcovEW70{@c>?Ig4=!mwVS&&AXzQT z+_XnOX>6GY`HN$2c=iLIYQMfk-a$c>Q17>BU+t_}`( z=O5!wp5_&fQn5_YZEPWva|6iEMmzKT>Z18k&pKT5CI0}AaU!Ct#$+rmBpikG>x>>h zDw1Uo#9Gxbg#$DBgvbwYJ8dMNrxaO)@>DZE){T6%Dh}$A(P!ZRK&UqYz+nEAIo%QL z?Ds0PThZkOV^TL{^SdLzPx1vz8J0B>K@>8o50PYGsu!s_^%ytrF`QRJ?JQ zF!{x8+=23po-1`@B^7eF+24uwr=Kll-ws&c>=Tkn;ju zTL_vpf_cCUWBaOc*Reld^zsOo$@!Wv+(_9B#8l_ZRT3-4Spz66q>{g&>x!jmOuS! zInZyf_cYO#|zRvA5)>lzOpWWZU>ojs_qTpbu1aqA5 zL8pnWOQOuz4;swOVR-z%F}m!GobJN&xbfH0tI263fnklzY!`RWAW^goo=>Rh>&7`E ztD_YkY7n#e4C;_E&g|qC&*}%YQfyp|z9uTc?O_b^76K_;fUBP50y=cZTzVYT5xg_Y zEN^Znnh64p@dg32{5c Yt8Qj_s`CmQ;tzw=x7@B*sj9>@9=C4E;ZqMz+!!Zp?*Z zGB8z@CN0N5F~A)OJg!eqU^G=4AH0E~mg*pz+!&|bar5Pwdyao9iEfn78cF3_!p_03 zB>w=Gaj$Z5pUawaMK#5<+}q9P7L}FWHY&LXk@ybAlFkH@Xo8l*GkJn(08qekdv(Xx znodoU<)P(qdD2Xx;navDI|PHBr1l5jn$i1G+dyQ1tdPYtn_6N}2*B!kfsB)mYd&~_ zv?X1D5(blcfLb%i#(l7V{dFut7@{sxSy&JXD9C0$!#|m>3QqAVP?KY$XIU23Yj%=G zQzqg`Tx4=iJ@_BwB1sL!WM{4gG$S82 zW&s)5mDyM@Vh%HroaB4=u9Z7<3Ut#&lCM0M7`tGL`^$-^$S90{`-9Fs=!#X5o(SZW zB+kBLNTG77azHE(1Po+z+NChr!d~JjXPP#b46{ZQZBQ~YGxg`zojygpn{C8`7}iCQ zN06kP{$QTJOi<=*(?l_(GuY?IsH)~E8JM3o_m+S%Eo-pmi1AVl1U^`uNVy`Gt(aAV~WyN z{p_+z2r0RO5zvmm{;I`G7$&>KK4TXOv8ocSlj)2QbLq`$#Vpdx_HYV7LvP#{%w7mT zH(&n%T?}<%)Ln!+n7TI&HLOwz4%7l5tXPb77|G+kMHo^gft=hxp^Paz1!14>9!@>G zb~O>23wfl0fmOKLqs+J9;QioFalpv@{cKxAW_cqL%95#MjbVjZq&Uiq9+^C39Q}K^ zv~WT)<{qRvPPa2zS)^n%GCXY}L+!vVfl=Kdc*N1Exgs`cE&>LQKXQ9y;0*fH=JMC< zakr35uv?dil1T56Mlw2a#sxIRn|<&|5+OF%MqoE^amIbR{{W3STcPO2DWPpx0ns$2iYkYAcI(v5Ux> z+}zzV9lv9`R*hKp&+!a;Q&!8!mN@+6^42jTMrI1TvG;P=86JoHD<>H@xy3e6NV+)QI&#SsYFN~s{QJmhJ2^?sA`-g4|XPo~4 zjWSprt(I1lGWms&FDlE=G?PfWPu?uTwrw10v9y;m2EwwI+vrK?J-;7HWXt3#JX_~! z3o9hV#?0C01RQbKB;(et!58`vXs6p8j2~o~T(BH**CUb7uf126<7-JFh^owX!yp+9 zz0W-eKA-(+(lK&otx2N7;@zf><)fBGWmWR!9$s^TLoP#nx#Vz84r;85_fty#SQf-G zLn#C^DCeg<^yq3CBAQ*cc2LFS*@XzrHpON<6;hz&0newQ;;ln9#8)0u2n6xrVGucG z!RwrX&UnYtwB$){V+b`Np;hEfz%P`XjPg!+qDf+oOri5-RBXuj+)3&wE(*uxOB|v{ zGJNhBFvvWLY?DbmYvwF5vOJ8kMhdppJdB=y4EohwGo}ztZa&`PA2^1OaAsVQ#u#y* zemMNSD*X2jB|u^FgfbO&Ck43c$5Dft#)0Az%9k-ne6n^*pKy-Hj`gmIaVdgpONfJ; zc@{^wK;Bv84mrppzhCE3G;FAH^dOofOL-zdaRlU}%OPw6azM^__WFBOwen+N9%O+G zA&I(>?RLoA17jIEBm?P8jiR`F zRUZ6`vvKB&SyV#-Mf>XU0(TLRz~DC>c;na7r8yv+nnCHYNB8cRbmuA)4yGhzH{{YsfhVvvZ5mZSE z?2>ick?20XdGxKR$;k>cY?=fKCB!pI?#Nn3oG#`p!HqrfHWfsUMnFOv)BHTGlfoGiQQEPaOtFKr(8{wjd?0!ooMpD-1|Od-Wrx z2T$tUE@;ysXWV5#?uu~cJY*d7KI0wgo8f8Gbh4PhKfG|q=s(YTY8o1H>RS0CLeAeZpx7~(^PYJ=hO49^d!szD znIOPvVmZNH$32K{K{=|T;w8Be+{)tA1NM#NM~M323E&@kb>HtKjz~x_AYtZtjpi?G zZ5=@blb=Ccl~jSoDn;$K{{Uv6e37hsmPtI|a#!p59(^jSTtvQ2vMiFzF_Cg$a-ngI z?#2gEj%s+q2}Ejv(tnyF?S=}ybJPNO;PcX=mfKMM3}oCaVHN{>;F z_^PKKQ)sIp12KOkS=!d#4Uz6bS2*XMFhTA0sUintG0S-_7jS|G0hTez;CAkR6HHXO zRku>)!7DIeKq?#fxg7o;^?GGt=Uf|RG0Ip$aAPka)&P0|Py?ime#5YldsDKH)HYxZ)xrTN&eWo<~Z~o*QPlj^!Y= z{?LjO9l8F_c`g+ggCdE(>Z=f>spReStG4ZchFJ3?dzg8Hl{h))@XctZ%$qDlZqmmh zv+TgzAD9BMY#w;WKS4`jZ47LpQqwHJyN$f<1Ex;^^y^SG$Y6?OmPVT+XkJD+$^5EB znF*1CpEY9{Dt4~k+9yq{>dihnLfMjP!7Plb**uJnY6%%sz|q1s&dugQ6SD|MH~_IM zz;pzXdS}+5%+fK?TZFwxyy&c?`xNqRis4X=&M}l7j|V5Xh z+gFd_>OQCO=BZ5>nl;7D(1gPTiOg~-&j%r|(OJnvpNAIDL&gMx>rbUdL<0KsL-Mxip$s6iuxnpvrm-;-CDS?*WSlOl-EUS}@ z`*Lyk)oG##vhEDiNgDl~gYc(0;{?<;gj=TQmTTLhs~x5P0s8FIQrLocB!=MmvcgQLJegu(Op*fGQn}!aat}B;?kYH8 zQdLz#%*-L5&)E3{o5xl|`HgZO?q`qg-n?tQ|>(s}PA4ZKGgX&84uPH~=` z){UuH-kc-KPV+`4NNz^>;f<6=k&KBul6#Jr9-yA}O5lj3A7q+&VM~Vc9pMp`9At6S zbDpQYOAMkeCz4d(xuzokE_fq7NXM_Ks|BPC(fJ5%b`P^$mnDM?lAv_K&VK>#m=mWP zlgn`&Nj2DZYl*<$8@72p&wTsT9(SD$%CPzF+BI04oUr~fM;w!p{{Ysg+9P_UCjlLb z`C$j%Ae?;;X`!7XbR51}WL>1}$3y=B>gV&SNphLS3Ea_p1&R?bmmJLu)0>nwTut)zC7T@wLU{gF%ThYCDMv!|B4VCYv7}FxEg(=sVB}yBa6#aa z>sKUIh8X4ynGzskc_)#{sy5S2aIpE(e)c&I#RwUrT=EZI58>X6y_3ay1jEUd)-+^x z1!M>2wBNg(O zaM}ka9P`Cnw|97ERkrhFf8C^s!!qNHjN|g=u#LQXS-C>k3LOh=Imb%hlS84&I3#b# zA)Nt)Y)>cVSwOa z9+c~7=JKvpP_5vFmN%D}!j8SiKHcgFaf0e=nIW1cRk?MRNMlq;E%zzF{v*cR9{&JZ zfl}%K*)WB6Q9G6dpI~_JOB$H`xz<>xXNoc4`_&BTErkcLK` z!kx!B7$+wlze>idF`QNR&`VW>G>QVer2hBk3>m$0I6s9=Ad%xCW%H1>)kQg2*F31t zZ0E0XYLsAYM}g8uM#HF(D?j-3H8h~5t1-+@&RI@J40$!r)aFUIxo2$A=N~@ST=|3m zMtag4a;9k>Rx?XBwdqdwT)ex~aiM9Wji%mlkt3?%_M-U%i5G2XDi*LnL6b%MktPfwLCn zEEhjFJ&s31{c1rNc7{NY2ay;&Sl%SLj$_6ow$`&J+J{kjX@w^H+UhU))kweuo7z?`uelaBDx~)M zgYQ$#Hu;h?hDKo;vjzYF4tV^(n5DU9j#XKeJhu6RagmBq=1XGJlL@WbM~dJ}<@~ZJ zMR0OE=dY$QQp2=)P{V*r6^bP8-h=!qgEKsh9Bv~}>e3d^?!#mfM_hNS2H)(LDL)A3 zqRK$r*v}m~BBG^4kur8I%`cUL*bu{R!eSJVTRl&wr{n8OY_k+biIwHT;sxeKQ{3l* zI`#B5ucTUyNY1Sr#Ik_L%sE}z#(4aHGhKy_g0{}V3`LSoSYW9h$DTdwDAeZYB|me_ z&(dt8f(3@*L$~~~XZg0Ta6eu>>(F7ew6=}|6lfR8KPhbPW6%tD9G-nCW77ipKPR4n z*+-Uvw;ugJr8429w48`-w=8Rs9FA2+c+VW=dV%XtL|~-cjXMx#7co43QbhPzowLC1 zKbK*`I&JU;Nw62YRZc5%e#f<4wJk`b0HCcNXJ3TDNd)<`(*U6yadS{amgx2 z7DTb&EN6@p?Vdj$YKKxNsX17q1Tl$X659#c17)H?m2SlJ;QLjun_`uv8(l%`$2D;Q z4+7vXo>-Bvf(IBUj&s`{m5HiN9fi`e?^IL`4l>d1{{U!r1JL@^NzP|9Z_T-OSejVT z14?6Jxbqk(Bzo`%U*}Ao78dO#$L^i^k>dU0`JL1^8;8Hp)M+8OF-V)r#L8q}yM_M% z15oM;xFrE#paW z$bfvNIG8%*cgmb(`u_lpWU7=A8A>kHZ{37pw*-8|{oZqc2cgeu*Ri;Q24yPZC5f1o zfGZX4fzLlr>sqNa%{dvlZy1>^B|05i=rO%kg+NP!S#-Oe`q-)YU1aM^7a%NZiHU z`jOOU`hHaCrix7b?1EIr#U)$t_xBW&!VcUrs9(McWR*M*OdR*9lw5|Qu4G(FlNmD; z8B`*%C_we&Bj2d{Qo>nf5~Z|pt1*wy^RmQekCz<>Jk(dw+)XAU`QzgmY~_bR`O$3& zQ01OwWhZh*z>IxPcs{k9Iin-0Dk*Mh$03+Hhcbt4vIPJF+2}tn=bmdS_TqIr#H?X~ zzG$}-mi5O@IsX7Awh*iZA_sRngJT=L208hMInP?9e-jv|xeXj^4(7~?8A^_MuH`GF zCekyk?-hLJnns8#43|=%gU)&ELF>|}>egd_+SBB4`?l=`n>hS&PrHe>FqYX<_h%6! zo$fk|so)m+ z^V2=^+Ka;oj5Dbdq^HY_t_dUbJ^uhIhCExeu8A`FDo9h7V%Q}0#~D3452ZQf^Zrud zC0NNx3i8T(eR-*j+hqGhjPV?DyunLhRn#Wk-@H77Tb7sRIFZ5HQ_DpJZacbk`qeuq z(mB8zcdy^w$t_z?6l}qR6px*%_}s>{YAl(_NeoR){iDi>ok(xrB(J|D9-x7Yclu(9 z+j+S2TYE_0pijKR9FBPB-k?RA)?0ZXhB+mXnRYrWZs3prJ;|aLMM)M`RY1}++{rHF zjAxvalYx?P*mUWNm&$WlqbFdrf@LZDzmTM7D$1jP2Vq$#41||rCXf*?@TeQQ1I~Ew z?_Fj3+L&c74j@ouVyA996YZP~`kLf!u1rbu8+(a19p)HJYOBWFcO(w|&T1CtRVQ{` zNFE@~6~YC>ZZauvo3Owm+~l6sZLR~vbC}{u36gaK0f6mXqudrrt`beCBW;n4kWO)e zI^=WtR@5b8u`aSKfHCtxLI_-SJPy4${*|J4E~04_zS7F+EZCLQsY1X4!?tP*oB2M} z&jWB~{qmx30QTf`=fC*W=$>RT&kKhv`;e-JAOq6`5$%e|zG%rJG?qDTXI7R-G@QU%kUL>^^UotYfdi);_p4)S53=Go_BPbSrJ1{ubNGx7 zFe@th&6!c4e=Z9}3mvk>kU;1VWC73hsYs4i(mHzx71Qi-?};Uhv*VITIL{r=Z1d8i zpH7+}ZY_**q>-N?L0>VjPgTh)&#(2YSg#gm`!t3~cgMAdnpKCW1ac3iD_T8GE_|f6 zP^%DpouE7CfJnwq1EzTVO=$+=OQkf=I@Pt?u_VoN1cX~gH$@RD#Al!Hvz+&;*Kr8rXdBEhqpMt7q>QQv$OM7G#&{>zuu|?ABn4$# z$m1XD#D$ef&hUK*C!g|bD9%zaZavQHO}}_hTuq1bR0Unba^Umy2a1zZ*LOfr#H2P1 zjJU#{-A?mfM_*L3q(*;~aEKn>iWEyE%z#$*8C2**9L zPrpv}y*tR>Ekw!FG#hv=yy)XdUUFoTMvMlTfD6=hAwcWxRuWW6-_~`>k~zHG-{0*l@9Happ)DZtOz6OKDE(KDPKZ)+UQyT0EDV3MAu$wO$&(ppj4@i zfXj@YzvtGk+W3|$lCsHhmwCxC1l+rSyxzZ0t$60Ur_W_?b2Je<$1{0;V#q{bkG-^x zG6ByX-1nnNoqp3Cji}yQ#c=~Azu8o7d9loGyQ;9^faC+8YJSnhiN#b;q4Y)lzMtY9 zKl?S|Np0i{zc@Qoo}-SL=l=lLUIF88gOfG9Z=^#5#VyMu$@Z*Bz^@x)9ONGP!RTwW z(7Z(|vfCJhFxr*ik5B9;zgQI+kf5yL3i z-27ko?eJFOXfAB0j%$hh(<09CmW_IXO8|auLC3lDug9N={s+47uB@=!rOdDiWO&rX zS)yU{eeQVYf!Ffm`n2(%hU_&7FX6jrW@w^be6TjFaHWUTW8Bx}Z|w#9JSFYcqpaJN zj@DOGac>MEyvaex+Iw~f1JqZk3`}b`&g{Rghv|MF@t!Lu#`_wY(tY|LhVtB5ysTDf zV*5niS&}%35%nYy*B-T@;h8TqNR8*(;V&w*u<4{9IZzXZCnNyFpgiNAglD?=f$;M4 zNYtcjdw(inc2eRQA7o*&cXR97yq5aP_rp4b!ZeL9Ax+lgpR^-5AmzarZ%w^0D~52V zRd4to(^w4FSk=o3ekapj6Zprg=@D7!zifLXYm|G15N=i-fl_dKj!&t@eFvrLpYV}h zeWu>-bdSwLAIz$+!N?u=4^Mjh z4-ja!mkj{7kz33ALY9DB6~J?}f=Yem!Rk5@#c|4)E4|Jreutxpo!Sa{3AnuddYqubqCU1k_HNl>#W!4k$f+nntr6(=D` zBbxcf4;RHf+;KhZ7gt$P46w?;Hye%vVCOmO>F-*)hl}-1JsWJ2NpBphCBQ-Z#$CDm z8+TH3-`2exHBGr${MDcEwjvdzrDpw4$sgLc_6KVz^(}M2Hg^{?UEH+Hg2(s8hXqK^ zPhbhjN22RoRr(DS-T7C(^QmnGzuI2v#Jl9ly6FQJ= zw{x~Yk;=#clrdG0X=U{_97}KJo$;%vX2wSBH)?Dx9nG}oW5QyHd2+LsInO^qp4C<> za^LFRHiryk{vzJ>X@w+x6_tlu(6&eP6+3bz(*m18Tku`C8~SP|N$P`>A6B9O8pz-}1iE6teQ0NfWn zKc!||8CrY31E@t;Ey%4VF~|@D^0D3JF*s$UoJnnyZ0RHeZuJ1S%zwlD^rnrk2*ipQ zUu09Y&AqbP#>~*l5AQvOIvjJ)y;rl|_ZKqC#~xCU8Mg(=J*pX_xOG-UaJgKPhjC&2 zL)+f0y~8pp2;D9u3%C*T=cOlP_c3bZ%)V^0%!&bk6`y*Iq8Ip_J+^ss59HtP#VIx4csCVTYh zT|SxM{a*DYn#RWB>Q)QBI9Dt|uh3uF>-HV-$B*=%_(}B$5s|cH zj=!csu4z||^mk`o8wXPpK2(pGz6O5IJ~H^ntjnfomhu^GW>%Doa>~d++(E~`ROEYR2EFSRhH8_+YFY(NJzjeOB^1oPkwxc+RjUqx7Eb0X31_=MH~qu zCym3NqtmhGxou~~%M#r>hqY@B%W~}4Q3yE59f9eSjtH)=W2NkVi<0oVscjCw#Ttv< zNpR3cVzgO5(JwC^I8d*A?l}ZwobW5mwe3m^3zoDdLn2$p_GxW(1(73>h8&kchEtM2 z9WpXbGI@BnaY#}U^0Ii z^XoMSvHH$mfR+xDi+UGcFeoS*wU}tP`!~NwY|3cI;<9Kq{ggr%6&mr1Lhu`$6sUkW$>fM z9wfKY>?hGoI)rW}yIXxtq_h6_4GT$d8G|6)cVqB9Yv}vSIBnV`c_1P-Rb)umNw{?+^dOFd*!tH^9#_!( zSB^Nso<3_2Mo!CeYeW*j>2HT3HfYeHQp9!Z^{iX4=$o#C2AvA1M&U+lqqMqNn`2A9 zbLInfPTa;vIrlyNY5ItU_EBt**g}HebY|Z0xK;Ha@~1pwC%3J2d#B}`w`ZSAHJlrf znbqC`v6WU~x9|rBxw&yH^G+H;Ac0Z|gKbsEOs{-_?0K%2QnZ@DNinkXqid~+B+g@w zMFTB{UPAzLf$A%U)HMc%PdvveMQ~flfH5JPJ&7cdis!2|(X?aAjSE(_xhk)yX;;Z^ zvB>r*Zsui^IUjgn5J%!@NrLpIRRiB+poTHTq{`+<;u=L+mxDX zrFfbY2V|;nTX^M1bKD-^opd%giKmnHS#6ZhZl(b0cs&kBw@g*5h@+8Zd$_Hdcnn)@ z{H0Y;6a;Of13YIZsmVFXt_xSPlHTgh@orUMn4csu;Pv3+q0efmL9I>V?)S0k2J$Pk zD$`p(nn8>R#^pT^IOp-MTJ+JVHB*r~d$3E4fn2Ny#Ule{MdevsY}FQMC>vl{-5O}}iWNX%z$YC@{Qm$`Tf&=_j#)`btp?qAb{m_C#lu@9tc{T5 zV5;-RdNxO1r{1XC+d}{?1W$7!+Q%f382;-Yyv4KXMgbp>H7)eY*K&Ey4ap>sBvQDL z5skRxBd$rICL|VUUDhqkL@L=Uz~=)aoPU!}e&~|W&$`l!IznS&mm|%QvT#_8a(zZ| z{{ZT*KhzRyM!55B=aS9`JCH~tDnAf%r<3(H>sI=lEgXsT7K zq!U?5703|F4Z9Mq+j8Iian22M-2%&8N(cj%c{E-z2*GQ_UoDY%6Z1<5dDQkpBP*X`)MWWM{UX&5>kTmOZ7UBaxB;${sy32^j|`$tJ$@WAY=K^Ceg9G8mOgxhI9> zlDNUi!33T#0j-@sQfo$@)HHI3vt8={05IEM?BSIuN$z&qxw4kT zTibbp-bE#Ru zW+AKgd$C!6vPfvVwIrsLgB=Gc5TiiVNHhM+u zmV25jp(K)AGY|?!!A=_oKRHpgaohu`Wu#cxZI5x9d5a{D*G5GJeKGRkiS6hrq@9Sw zRgGSnleNN1R^i|YGR(?XBMlfoDcjFqe#B<7bxktT>e|xmY5J9b7YwoAPRiEuIAOnT z2I5o^k?uWedz7BqIiF*055gxWY3cOmzojrwZjq{mxk%R8WV#nJZdHHc=Z-p@cIn$S z=3*rIwK=J_*?03HD8gPu+^!1vERcMNwd-)5TNx-i=t zFbj^PVDW?B6%kHMw|kwW7l^4Xwe_9US8>}cmzIUqnmF^cK2(+3*#sQ)Bfk~PUFla+ z-o>POUqk%Gag*HJ+1g7Moo=>~TQ89+!Egcu{uPce2g*KdkVqdd zsIO1((%W3e1lLn4TjfeL@&M;>$R$4U01ik552+dSDbt)%xaq4s4?dq$T{32dM&B^o zA!5W3q@1Yye~{-D-dbEmsljjd8_Q`DNR-?>F##hH!zo~JbI|d@99CzEygO?&7Z*n2 zB4R^?Uxs!Ib*%Ok~V%Nv$I=(k<;RzIH5i_h{w?Ez^ zB=!TJ#MbefS{&*YMrMa&HRD~a$aHBz3nZ(#c{%#~f1FoGaiB?WJ)$ApfybBSMoO>0 z_0QI}tk~PbI?o(x(5mk8zVRd65zZ70_s2bt`872h5v`cm ztuJFonmI~KYV4t+!!()5!8z#N53#Q=@urfEaFX3bmb1*oW4nxCj19$9^yj`a(!JHM zWR}JYqiGzD)Onz#z0L*}l5P8Ai5PhoqNUL)cYZB%bK`qu! zWGDEWlg~Kg)24G)Mv^WrH5=(P*zT>Bc0}!RV-b>ga-){xBLMXvlYxTWGQ}jkGhMpe zLL*VU$=NS2CntOGG@k;h-h_2#hj zO@3WoIAeGk6ZV!!m=C-cfr1Yi>+6Hsy$DXtY97i}FD{3y+GtmE%N$RzK+F66vF+Q* zAYkVVF@i^-^{rdY0@`a?G}&WlDaau8o2>4g+!RpTL^!j7U=Ex<)UFbRn22wE`|3{{y*ruR8kJm=Teo{^cRvO;A>^D{QjmkK?7 zK_BOePMWc`JGh(HjOIj^C3UtXx5I$DjyPr=ayb~!b6Hx`%^IY8m1El@qB{+s{+#*> z(6&MLiOivz+-+n~O0xn_13eGcvbF12{>L|(vAdQn8(jj?mg=N|gU4Pf6ii;M^Q)_g z6&&UuqI}J>49wq-Kgjl|ts%E1zRPiGdLG=Y=pro9oaetr1Y;x6j)dhQySJF!IDuY! ze6)&~EZ^bN^sa|Un$GgvG>bGhEZK@U;|#bRa!K_)f$QyA&FSVTE>48j5XWykO*@1F z1&ybjNda@8LyYyvu8!VOIh_9LC?y4UWSo)E@=w$M0M|{nP#t2KtxLP85wm7N!RH5z zb@l05=E~C0Io}+2Gwp^XXUk0EErcBW*vTYzQ&5zVkGF-)iz_%|Fzy9yt>oJZD&cXS z+#CwrSfq?gbFxA(%8=)4M}v^wha=LS$qOa3H<+@*!)!YNR?mFo9P}8)Sh{jX)|Jb| z$IMvQXdv|O&Ik4Mu8W$+(hE6dX_8qPO9=vkSQTa-r0{!H)s6`zWqrPEmw{)W?K`2} zoxQW19P%@fj8@%ghmAl$6qjQp=;{Eba2h0W( zDI|3xIrgehF`b}zRL+Jnz}%r$&uz+k_rdNuRJPGN2&61sOO=vG;Fcb^$6sn%nkk(T zlgx@K2xf_qKx6U%+;03i>Fz7$Z;RRno-sAN2+}O&io!OtE`DGSt~wK5`Efk(3zUJ6Fgg?) z<0v-<$irg?@b;;!p|?p(PF(H`6iXN?SE>2C9tRZJWd=94F(47`*yXdy{JE;7%%{xe8c)ZA?kYe2i)(h=K*D=h}Owu#R z$-S+g836Ie8TC0n^ritR2tLy^lFZBJM3 z0P+TMa1R-+V$x;VHMt$^k{Hw~q8TNPh(H5i3~~qLO)lsnRJT+o&6T{_C0vlC=Z?Qx ztnS`Q0Ln;g91=(b^UYX|B`zatl8Xr*TNmB(=W$VE$?l0-adv&DV z%#01hE(Xxr?pTe{p)sfjt~l-2@WnCNL`ag9pUgm^N!^9c-1gV#rw1gKAY-?$H8xCUDfg_K zO2;u!7lEFjdk(abTu&6LV)EE2EDOWtE_2s!ao-fuNY)KlP|FnYgBX!v3<5~XKse)& zaqm%2a!k;}BS(+3ZJ8Amvl4pybjC$TDuyxKMqOfO&&~?59^3+eMU# zl@FOSXFHhW;eg`Zi>r z(Ymt+jyzzf=b`J)Pro&I!zYyrG+uSNmn|Ha+|CYHkEc1P?&CKS&o|kUDI;}ONZTQl z^b4L&I%HQJPGqztHfCHhtcf?DJR&d*V%h~~Byo>UPkL2PEYEv7&vzrKX_7X?gndr~ zc5#ziap?CGyg|gN8H@Fx>5Zx(_TR4#BUrx{k& z9cHx*cTDi$7EpN^IUJ5Ucd6`PX^zxc6sc|dQ2fKDE74lsMoC$Ob8NI-vd0Kf8jdl? zuR?pAp7i}b$z8(>c;XC<&Zs@;8Ju z+-5lc0C-EwB9%#|W%<~5;{zudh>Mal8q3Lt?OUUyjx~iO$Jh+V)AA2MFyd3o7 z(yzbTQaI(5qivKVVPo?MJFp2OAgSQ`0g`FvD6J4nH0f^mZ!PYDk~Pn<>Cb9}PVpF@ zg^n2Z%1~_$$?ec}#~$94*phcA#?d944b!Wu&aucFw?KW*dLRaKaAuxtvHjRm0afm! z9gaU*jteift;0$uMV3Oq$00&U$mE01UiGJDh6sUZB;3q4jlc|gWc_>4ou80hqA2a< zNm*XzIT6WZ2H$B_m>E-MwT&7<-f>&|;tjyE!Tvkq9dTAkl2l=*N@NgXPP7qG&sEz-*x z71~*V&N>~V9XaF*y{IkBQb`<0S{LAv$wl?{^x~>chDMEDc7=#;D47AP2crny<0XY2 z-bRI{9%G4F_7xkm-#u3cr@c#LsTn_giO-ZDB;(h><}D#(6QpFSk<@1deg~h*sUw}Xp5@5o3`XTu z$MBQX)UL@KZ7j^OMH*+!kbnWtuW!bow`@x+jE%ZUL2s9UdU4+!KU#IeKF{7Vvojs| zTnuN9=e8@PwC+mJoy3AS?)}gl6WG>jG-ZrWwOSqQjNY7QCy!2_{d&18fB^wc5D-Zq z5&j~ijucjp%#Ie2Zp^N^Vh=x0f52954YIkcMG`YAnH&Hz6@VZfyniaY8Xui9tM^K} zK28QY@G;MC)~iVh!ckN-fae^NGoR9)w=B3;O`s!v{Pe3{>KnYqys-!J0R8GNVD*T;#It!QIbNGhHLwS`}w97j~C(z)&)`KPe}!Mk^{w6%toTW3-A{*<@?j zWRvA=oDBTkaf8kVMI_0jq}nsq;yGq4HhD5e9^N~KD8)(YbI4!;;Qs(xxYEp0cUx!q zw#JNIMni5Oft;VfeQ{HwZ4tCC|!a9${GkqYC^P}^HQcnK$y*pWYr*Yl+eK`87Yg##=&9IzPM$3dE( z&Vk-}7Edt3yK>NkEZENgao>_Z#gr7+`Ud zS0ANf-RfnoE@rn)rPWttK<$hUy>r{WQiai{vx||^THo6uNjz+l0Vga7ZOSqa(*$C) zBD{v|6`vwJF)SFX74{>M_*WgK6peh>WDy``h8IA}szJ^V82P!!G_8D+NMnf$LaZ2+ zC3)n2M1M+~SS1w`r(4LUk~E8IBzO_FG6?iPOmwDA3M8^d%G<{6@<%5a>B0X116h&F zYYa$R$c7@!$eW0c5HrR}=n3yydrXmBES#znz16do?}88ND0;J+Ta>R-*rw;-wF4`L zQn)=v-2Lt`$nTNbs=UF=I$W4a1;kOrsy2`B6a78v#-Vu&#H!!CW%+Gm##u%>^Nuom zcdScj)RhXiXA)O@I906FW4*I-%mx;&iVWPRRq z$Gvjaa!jZzvKbb1fnV&`H&}1nt)yGsn;d5(3}*nI!Im)?|hEB5-#N-Fox{Wcy>7E^U}Gh#>Q%2hDd?7+tx~KDYp5lg2vH z2Fj91#m%V#K+df5s3k%kQ zQv^^-PT3Bq&N}3J8m9Ve!by$WB&e{TG=No9_S?^FjzQ`Nt#n)>*K!+qRc>}h zkg$>>#n|moxXuA2VE+I<-D^@Lj_GaESuNHCicQ{4!7ay9PepFP4^LCiFL7fW$q-`u z7G>B3tf1qlopCu0Z7DJn_$7^UHH^u+JQ9s#Qv?ibx8q zcAwLVWMst>d8xe#BN33QIpA`0{{ZXvtffMn&Q&PMvzocmwAorlmLjcg8|Gv8m%sV? zS39mHlo80T@xq9k;*MlFkwD`Z1Of*<@qln^vUyqVm+abfzHyC}5=9Rq6Z|Sc1D@H( zZ1k>HT@D>Y$!|5<3z@enTF7@u%0cIjG1sB>uOAbaQ*mc4YAQ`?&y9R#;){EOsoGm0 zo_QrO!*?zjW03Q_j;x?(J9=lY7_SE>;y;r;lsaaWe783xcS$ses-zq=ajr`h896PE znd^%B7f|?j;wZdfJTSq!-I_+RiQp0f103Y?xFe#G&po&u{jY(WN`}VoQ?OeLsFq08 zC&7_ao<|wLI0qiXIL0gT4BsfP3ex3^YtfvTtg8))p=-as$LFN}I@L7YSNjuH-)SX) zF{~v#u-M}Z*n0l}Q(m*-yQbDGUM8B%#IYG9l1r%JUIEC=gbd@1bnV^A|5iKK*1w8Ad-2> z?Oa)IS&x*|V@92?J;c3&&i5e-VoCZ5#Gnv+%ySxB7LYaOyr}a?EaJ^44hw8;f)V0gh|# zvba&f-ZeCrWAhwdN1QC>)RZ48{=E-Ng8NU^ts~R*R3O}5GTP2nS(Zl5Nhgq`;A5P6 zV>OrYBjMJa7l)^|pBEQF8Lg&-hK#dx8TFi)aPJQ1_AG$N8?{{mdcv7nf6#~ zQ}sLpQutpjqow7nax~g}JHF8oViF?Q=cvZ)4twBL&ky`p)BHJb+D5H!aL~ZJXTLxd zQyjML2_Wa78RoiOSK?Kkl_mYQp)@IH_7-g;&X@?}!6#q`sT`1}sXS+)_}Mj>d_m$J zN^2iKQM=TxBu^_O$#CO8Dt6v_*V|#LsKr?yf5MoV%MtHzPM?w?c&vZzcShI(5oQ%b}j)^ zo~I=9>BVa6Qk0vP=k*5(SHjVv`LB1j#o^;$5y>KHw>N)h)9+$=6pKP;@%v-Ajeb5)WCd0|;|RF~f;w&oo<|&t^Re|Q#w$bg z8hFN%RI*K@D&Rqm+wx^lyN ztVv`a%(}F>nPgET0IWAEf>549wsz;(8ut$bcsA_GX)d8Z`V_4spXiYvBr21&PD$hs zmpSz#jw!w&vGAp{==037i=^_)#Et_vBPvM2Jc2p*71#d&!raqz=@Qb%ONUZ|OGx3l zwnoTl7mQ_b^Bw^s2d}Mqk*_C8$G?HER-_bRO!WJmCga6+cb3qq*=bsRtEyd$2HMN> z08i4s9Px&+28pgsYouGpJT_7+LheUylS#@ zmIZm-nBa8zdE+9zUQY_XpKYjJy`9hcNQ~{eJHcU$?Z_DCzg~Kp`>ZucIw^1W9)2qo zhow`NJN%E&KZv?Lov(D%Hn?^$)h`7cj{z zFzRU0-KDFT=8hesoa64eBxD@$eTntIA8B?AHPn}I$$M*ks4gsCQWiN20MDFs1EP#` z?NZ*_J;mOVhEg=>BaiH`s}&o)1~~7WA4>WfH9vB!&x6izP@PFhEzS!2!glw1%(L7A zmUdwYiq7HVWnq9B@qkC-a((NgUl9KQ!V5VTml90!Mx;0_yP+rLU8kV{;GX#7rFGhz zLd#gS^K{5>KebvEdqE>e$_d&WfsB0F$J5%gd}-mBHR4-KmLn~#sryB=miS`8V{B{> zusJ++9+lgMmptRmEf1KE3Nd_|8;y`d7Mm zS5kyo&8nEhI*YQk_0FjXMk=`(P^?vzh8rxo>A=Cyig+u-8q}MX+AGAK#bkE9hBi+w zBl7&f^vPhSJxS@!eFNdI1zz7n6W&}#w=9sOnd1QtTN{`!>t41e4Thk;E1P04IBHJH zMv=9)@pg-IZyb@ssQrdxYPTb7Y!ng>PaA>826^RkJ}-2td1X1rn|Pi70Eyt5ZwgCs;X9istzfp2NMjQL zwFgztZU!;_HQ_!LzVVj5V?2!9G;fzC=*Nx^*pYyzspj;@#GnzfQQbnkX#)0CyzzP;OQra1W?0j(Nv5CcEN| zFUR_A#fwDAXz|9k1|}`C;187ixI7+mJ6B=hzYX|gY8r*z`akw$_Uk32Yan0VbH+|{ zjQ17NSol)b#!HD|w0p$8mPz$Djx!;Jv4xS(8B>rm*O6ScYtZKSE%+ZxhNnXfB~mf8 z`=2-bJMf2zbc^X#H4QytL>(9A(!$Y^1!?(-(yTy_T zJh+Q7jh7tqInQs#x$Ex->h|6vhf}nc;dH?Sd9i5rtec7GF}N@Tp~q4&UCgrRJ|~rQ z2ySk4tvb~euVI$yS&0V)nSdKXVsYpQ87DQ%TD>}Sbb1|C`SDeiOX~jsu7~E8{gmsf zCbnRYPit9ZT{ziJU1NuF$T`VY$mmHu>$#i8y7!He$3lko`{r`9T)`kDu0}JQ_wVj2 z>ko{66!0o(I+I6pYa(0OG;$`Ih|Hxx0Dz=qoOK5$lV2NrJ5TH%6-Oniokv2tnM7u2 z40lnWZVL>M181=~$G&UDrB|L$U%(-OsZzXolalgRvGjL>d?Tv(8&Q>D))87;e=<9( z{ntt)BOowh0aDy!H~{zQUaJ?5{?BJNnXc+KHt?gYGnh6=uOkveAsKz4m+v9K&pk$S zbxR#G`$(5sXO`JxLFU^WtbStWa0etX3PH)~llby?8ef6$tt@uQ9+&n++X||NEP8?1 z1t-&>?ZtCTA3BfTdwCzGWqEZvG*oS6=#Ny={wHaIIfQ}RYJAIW2x7S7Dl!4jUU8bv zxA1p|bsb7i6T=PD+==Z(-8xp>MWb+M<>UTWc8^MnaLn&j1tZYo?8A z*L<$Wr5qxYe42UnKA6%p8zj_FURzqOjeTUz9&aL;uu@b8iGFCvDtLaNf(8h$4e@`4 zJTZN(-rH%iSxA=GOkUz2om6hY59t? z%yNv0pO}5(PV57YxvV3JtrRxObqFLNeB0ECY`%csZlY+qD zf$7OVTJ%2^+FL%61L?L3+JiAvHt_tidW??ad$)t=nB$uPyB|^1xM!i%AqN;zzGs@z8tvQrjI_RR|wQqDgLJe9NsUOyw^78 ze&tm*&;^ZSk0A!nyOJ@vx|7MR9UE5EAW)Z<(_F%#w_GGD(A$s*P(dK=ErrO>CcV!? zwTkb2R}ihNL1DO=Rd*?D;KsShBixRi^H|<9&|zt3xV3?8AyK+P8l91#J%P^y*PqUv zJY6+DR}!U~VZFMiC|HBRukTXsn8nobb6M=N;?UG|eYNp2z!M0xcALys>V@Ttq%_nu`3X(Mwc|Bvu^A0JDoeg9x>79YrE^~ zFt2j4#d_DDXv}B$nG>82d0dX1){^U&o_V&qkION%(WHPC+)&_w&N%}=OmSUKmGK`* zzk(Q}TU67e-L>Y!v<14Be!O6D+nfqyS}nEgGU}7use4l+Znn2Ge7%WKK|J7Bp6YYS z^D|r@5#r}j{caXsNh3UIwztt~*Xt>c`_EQHdvMX;Hxe*r>$r?A(hf<+dmm$2@LcKk>1}L(c$biQbA7TGg_bw|EDSQR9E@{OU+CX& z5Jv=aM$UhA`=SQXpUaQySXEG(-1h0_)T-G^O(S@(hOe%fNscF%1||%pRk{wIoq6^5 zsqA!pLgl84$zYfe*>_>OF`Nz;vBB$()#oeV+lb_QpS0bbioSiW0xGU^l{qAwV10XW zTiz1ZjlKA@g7gs2wZ`M}ANIKf5$J2ro(h{!mS2Iu#i>hchP|Lns zhDjq-xMw888lF{2=sC^@uf2Wc;XQBrV@kQWxM^g)x^2&MG7=c~CAw#i=UL&lazY(J=R1)V*)_0zk11Vl1^r2Zmf3@K3-dD_81)nO={NnO0by# zxWhDIqC0W^@bBn8zJ{zfo}k?b1--OLyOmswk=#C)~ubaE#zqez`j=woDjnw)A?16E?l@WGRhH`$X8v; zBpt{+AEExWU79H8mfVxNQ?(ox%SeAy>5uTMaYrY#mG%aO-rm`~&$LM-iy3JYF5C{M zx8+V)q<<>e$ie>rTn-3U2RwdR%~-aajrQ*){k&KFk2YriP@_Gu=B45acMJvyl2xIccjC&rv{i)W_T3ODI`_=^t$7rB5 zDm!C5jC25T%}Z|A2xp2|;EAC|+bc&O?->2y8}A$e)2AaHO=p)ofLCTMosA?|3VUE@ zBoAM&wQm?G7}(OWwzgR=%G(K;J1Yqti7eazxF8<6&rT`xLvIoygNWjMz!dINAmeEr z4n6%UIASD(htH4+fe~AwX*zH~I0PKy@T+5ND+;x%8&;K-Zs&}U(hp33667DmR~(b( zW^O8aT%kJ@Dl=y#(1^0Fp=LbrG70KEvN9?d7|UlAauQ`_P`SdAeMsX6ujf+4@k1o7 zGdn_Ik~@A29mTl%44mh;TClcaDO5C`SP-*Jv4GoD9>*Pe)x}urr3l3f3QZck6GW%X zjOT)PW2Zd8keJRskT+Jtzs;}q9s;zA(Whar2KZ}lY&04cpduy2k`I52n z#^wV61D<_-s?=j6DaDM2OPGGxFQSX>iZ@E|TzT7HI3Zu74EOK&)o_Ync_dkQl=*~B zkW;ZE_)c@r(zN2WFhdM8#pJw&Raw+9+Ie0-E|kmdBIf2}aT7-*i@BL4)D|Bxdy}~J z;NWwg#pd0B0B9jocAW6w1pgDOG5mJ_jARIqCH4 z^{Ps^QB!Cd3E}}-`b^*XWPXn!57@A~|M(G=6UvV2so|S{Bq-zAM zRh6N5-UW~soCS$~&eAH!)bo;5gN~WbPvZcW%Pu%+L`vRT#L=l8jt&k-_|)-;pf_^H zvMbxn5;su6RZen2_RT_Op5|wHrZOw9GdhMVfP0?Zt0bh&Vy-wzBE+Ux%P^3#Zc@w` z=dZR;N`+)1HHpMw1IR>i!lMQKTN{os#!d!LtxW{pUgwp!BRc-Z4ttrV@n?NF+*^xys!<=KPWtvz~qhx zL)M=>A7+y4GD{l>&eIfOm6Y~5=nqVapJYpe`?a-kH`y8mR%qlH`2%$;oOL`^2b%fX zLdb;`QBTZr%bur>2b}hUzv`QN-0u?d@IARZB@7lEPEaT$|BoU-X zEVyPWIs@sGfuBl+E>bvF8DT1tH}2RR7RGq==ku!fEiKX(%ic>A0px+U;HcqF0012K zJ^3{aIUOms_7xU9tY;xmjq2}}VBfA+^5&lv)ShG7eXe-zN^WT5!mNWQgTX$(tw%T6 z_C(OMa>^7n%&Ny~j_d3};QNZVYP&a><(VT5ADwEBWAh{W^!udXo+)w@CX+KQ!&*tc z5MZ^q1~54o&U5*So#2gCRg{~A1)_Gr!tsIU7G-7!)MZ$E zjE~N$UR&HqZDY2~zbNT%##x~xnu$at8aF$>S zu^jjQRcZ@D86+*`O69UnBn(e~WBn>QBxZYPuP2T>XPJ>0;aQk=KjBf$EADFBVg?dO z&hix55Zlh+$It`ETCWQ)o`wZ^Rike+a&8RS=zH<${uQ+_hSo)EMMHOQ8kT7y5+=|| z1gm6o)2DB0sO>DAG>+3MGZ4%fRdP=qv077iXv$Yeb^Xeuk8F`9b_Ky!&Nw`JfAy<6 z-f7XLRF*{Bx#Na2fZcF9`**1)Y3Gtzt@Ceku`Ds&!z&Qk9D6(F{2)=vg z%yQdZCBQ+G!5^Pm=x|Ktn|E58eq!9gJkKeL@nXZlC#pDA8N z5$p$ajB|w_&*%@OTbIszDCB4z16_=~z?F~ybAz1m$N4p?l3h&w)HYdUwRs_5EW;wk zxmd>Lf6I;Z|Z|2-f5?rq7Z*IKiW(SkIfP3^9^sMD1+8-iAz_(~jq14F|vq+g6ax;(* z8R?FD)y247@mwY4q6-uf2ri)vtlV+5f*5-4;PnR|g=^T@#hbTS?{zl2^7CVBI1@}k z;4b1-Se`$gXsH&^*5+}Hz07e;&`ARUzsq8wSpfj?!OlD#ytX%1dn9iyuXeMj?VNCb3UkG8Yxa2=nT^w|a}E47U=VTC1B3YY z>0H`ePB52Cl_iDco?j{nQA;aGcI{SPxKqzjj()zB=7EZ=US{cp4Ku_^+NwH@+zg(8 zcdJH7jE2q`q>|UjF|5qkW-aZUf;rD>sHrQo&mtg-+=$o9C-=a2BiFYc-N~++Iz*{P z#nTKz8;K!;SG9uO9i!RiFeG7^k&JxZ1~}=HO|yR{No|C31$Sn*mP87yy}0L`a%x!G z2_`IIRr76dbC4E3gbaN<`c(3q6)@U59m}!W;x-ru1e|gKAn-}oE9agtk*+{+yK)b z#G`e}phPOhbie_a3ZYqmdcj(1Y{pv zilZt;BBH)ymN^wftb{6(a!(ycUY?a^+2y!58IE1B5M_9wD;#U;Nj*6O@vex|lJp#C z$Q}lezt4mOVjwY-OBj^hvNq&6{n%1SW~7bYYrVGXXDXy2kltO0V+7|Xcc=q6JZB!Y zG*ZmBkH~AN7%Hmam6)E#2R~6&IK!7zY3%uW7C}%XhE1m77xzVp&-v|HsPa71#WWF! z;#Dmtn}*+$fETG85>IYDYel5ExS1YjNgCb}U8`H&fRc8Rn{#X`}-0 zWPV&~!rnJMJ7)rZgR1D6<@L|yu2}GnkY`wBIiAM`f*XoCgUW)h}WH} z**lna2OV+GJ%v`cog{$yYl6~^t=&NCJurXCt89z|?udCrmXNM~LH>PfC4OYh;T~Pa zth<#&kTw7lLF~TOZdviu)}xht$RtRn+GmY-N||7|>Z8z%;F0)JnI%B+MJ>C)PGClh zE#`M5^&^4DZfTL5k{ErM$c+(WEw%|#PB$<;0qOZyVzNjoROCb~iR5Q2WE@KbE<(0@ z5B|Mq$sEb$Lo|`x#R962nV2el?W>+REI}iTgX@~kYi;Lh`O#c1-OR(C!1m;V4;=gU z#aLl*>k4wLidQno56nrx3)JJBo}78cG?H9f#L&81qWtnD!Bvb5ZAD&iI`U7aUTXBC z%0VxfO2$=0v7s!?alpr?Qfr!0lV%M_fxz6WB##+MkC(Xi{{Z#>06KF<(lqhiBy3_u zTX_^N;tBck!;(1QR&DHZOkt8|o_2-Um&x4B+!Aru*P61D#RI9H^c1#*c1tM%SmT`V z2jSBqu-;)6D~^wK(eliwrCLqFq!Hm)B;kn|V~z(>P6sBS1zJHov!qWWe6mQuZ3Of0 zgY8mBX47Oqp&8t>p^rJvf1OBhu3{h)916lf2HsCkT#S7={HaG>&c#*PAs8~lJZ zG24`cv2LR$wM%t=r_6sk-c^Do1j8Q1Ty+HW$UGc(71XJynM#*235w7=-M^mhtF}nY zj0RUHSo@2E`TZ6i0ZgIu{%N&l~J*vcCzK&BWy}Z{E1`#xZ zL%5E)z{n(Z_o%|gw&FEXFh)#gYcU?U{A#T(=G5sWVq2L&U$MgLB<3y11Ar=F}&B=OLHi8W}be=&1_SC!q*QZwz| zt5a!4DGgv767LPwcCI#`*QmuoCERe~*5oQi%(oX1zEM}B4EF<&amVXXB(Yh`8p-FF zA&9s((FvTn=mIec+0RBGQyyq$og#F*ytio>7nH7P7)rXO%V?2_1(zAsu z9F~nh#y*Fqui;gh-r{+qxP*j;HC;Hsuul_t-X(cxrJisoG8cj0hz=y@H+Dx$-68oU!*#Fr5`Vq&}(5wmCbNXJ9l z>5i3r6+U~*<|=I4@*!fa+m1NTQ`mFbvZ+_h?Tr{A@y8sBzEb&tQ*d5E!RzRF{&hx2 zbdq)RBwKQy=Bu!+Nlb!d8yHF#W3mm+ zjB#Edze*^-b|LT%?mTW=?DC>EO}pAhKx2FJZR7L3CSs*o9XCe$H9=YjhF06N|eK!qstmp3d-6t?UW8a#vz z%mzr~0GxBhB3&~`H%1oK{&`bz481_cM;-dmX8!tF;&iTx#V&&k?uRx zH#0o;?Plw&-m1eTNX9Zc6H9Y7^o<;iWh0_TxJ?be zm{ogjUYkkpS#r&s@|CtSt=Uv27`bA1;GPbD`t`pW0wh?NKa$&o{20pi7$6*jxD(Q` z8f8J}&d^#w&P~kos8x*zC7aL>YSDRNlM_bMGs~YYRG;@|E=u8WG0u5Cay=^<$;J5* zB_SD>DM(mYhmd&;zjtj{72KiDIV3GrYHaV)aTvPQmWA)Rt_-#i|BR&ZqV0AWR$k{LjGXqalQK(NMrOBUmQ1V#QV;=+fjQiIkVj5EPJ30$xS(G$ z7u+VDiIznpB;bEPT7V=;Z#3*Y#gbN7HpqD6o}T`c!6Hff%ajv2$IChqhEu^D^Ux9R zS;@4=2)W2`n-N_6s~qSDlt{n}>VFDLaLH_9WX4C#!x#fO;C82e;#893WWHjfY>YQm z>^`~AU-7FktTIC@;kL;K%Fpur!#nw@=Vq!9>}Isf_N7p=XAH+EROhe&^~fWi@vR4I zIT9E0$&V}qhdD3b*Es2qYQ||%6fswl0tcE>BFx<5YLSu%IQhC`^Q(6sYMS0Mk;V2@ zkY%L%@wRh?Q`qy9+XL3AO3zUDk|cuG&Moo993iGVP2{K<)k)6PJeA1+pUc-VNfWH8 z5-Dk8xXrw94aJm#K5qOTfalk}5u!89V~oRZ6zW|t7&L%=;p_FO$&bxzxU#K1%QTW1 zFsiIEv<|+#Pk(M)UBv3SZd97(ki!<(<@3s{Y>|dy$J~s94;)l}Kr)hHW2;7eLG{5D zMLaPOmiwMRv=xnFjFnjWWS)w0cpqO%&z9*K`)OQ!%`9R!hjE+jY_o{e48}%3`oz_N z0Fo)AxPfh@5}k<@f=J_5JgUDWsK*5L>q`k^bu=&+E`hS#?Zr7?TC>bqml3x(iukLKOToXR8vK4 zSV;@X1<7OfkZyNIW9M!cqMYX^zaEsV*7As@F`@F`=MLW~Ao6qS4>TtiA|VOiVMVh` z48CkdE%M6)u*qzHhI)NHYQ&HfHkS_b$1S{I+S;majK;)}Ip+sF4*h%PqPUX|S(%h7 zj4n1YNU+Mi20-@4PvcCrlI9@ZRC!SU04{LBzP)qDty$A{NE+(t#1Tql zRFtMwn0oyWTz*wbRup+#A{Nj`IuVH0V0O9ANhhG|&r{EA)U$n-2=Zo3ruLama9rOz!8#1L)#;*BV1x{GFTgGl~%%Kv7B@n>(;3$ z0&ywK(cMa8G2B~&oyJ)=7Ag-ZjsQJC>yEWGtf(R%Xt{#M(HG^qx-3-`b$7rd4CLSf zarLJ&SxSZ7in7Q)eZ@+t&-v%ln>$A!o9yWg?W4Mgh@E4RlxH9Uag*uo*R3UcoiK4| zo+;sz%i8L55m;O>VCqgzKP=SHB(U7>SQ_ulGAu}-{oEW90qQ-o&}WK;>~0byYj%y{ zo@It4+=g;84i$1(6So-yxf$lCSd7msH&XqO5188#ByP!{x{N;S4CgF*1CDW9CS_42 za+K2#nmECNHd7&Ozz#B4bKl$F@TgG7DBI@^tbcY{`6nmy=Ayfj6MEZ}wXM9RVU_;# zbAm|ddzwf?>}I!Rk_em3wh}2;Whc=0!RTv9B+gkT(dCw^7{_T0kvH0Rc|U2KD#?yW z+({d-I(t=%8P#T$co9g%Pqof>FGJ{f?^Cs&V3H*A;u1$9$!!S#09LsND#T@aU=VZG zptV?2%kmN1?C<;BfOig`TIGa!VtT5aDmG0f!X^>~npLurLT-tUH3~9v$Bvx`QhHJd z(%m6Q;|Q`qyH~7Z9WW0<4T?c$`CmiUdOLJ`1HkDTa3Xh zSVwt42vvr0?mwk87qc@9sUdrYg?!U&tAKj}js|*Ue_Ei>`EnWK%PjYdzcIli0C2eg z5%kSFHjFAtDQ-(1rEY>Yk~1tY$+Rp-Ew{Mo!QG!<@U=C;m@KmSvd-%uwB0V!++?pl zpq@SIw2cH)2@)xz^LOt3-q=CU-5JRwWMt>K`qS9Q#A!4vvdE-)IUAdAPC)sGPB`O& zMG09M#imZbWRGG;1|DJ*tg@B~#(4A@>?)mT1K)JHt;p08~J3ID#y2$IpdD`?fTS^o2jiW{HbG(-C3krc6o)PBkD8l zoc^_>lC`zU?GZGHf<6X`0%K3al35aE98(5G@KYQ}W_==DPPqa%6Pi-?Ze)u+3$@c4!-`I~z&!5cZ z8*uM6+s}7rFWBv1IDzB}WQ?Au$0Q!${$TPdWqWAjw3bggG`WN_g;MOVjsfZPB=qO$ zO}d5yYGg@fmhBO<8H}z+pzY7TDxK7Ka9ccf&kXbVim^hEMzMjoyA7lh*8>9z#{lGkl1*tq>0=7J ztcfU)yjzatEt8!7Cxt)Ksx`f!o+%w*`+drZCi#@RDgGnhudPdykx$)5v@02eM7tuF z%ireh3|RBabJwTjDuTf$n;JgXGDW>0SpzX#<0K4~AdZLF_Z4AhSm&KknZ>*zyr2Lo zNyjIt2LJ)s=hm!QLnP1Vd0`#nDiLGc$~u5Mj&ahOQevl4GGtK5u_Hqnc%EnF)D6TA zv5fFT4iA4qDdzQ|xDO12WTkL}J5(Na@;h|=DosP|Q6tW*!bq4l6c!mgV18$Ig1;)@bE8 zj@bv4tTBQ8#m7vZPJK_UJ#^{T5xQu+e{bqo?2V1=ZDS)EwSqypF@86CmK4Qm-(xU|5P zuz&^-z~^_85am_4{7C$2docu4w9SIo3A#o(I6u?16D!@Uk>mplVm~cG{eFXw{=F;O zO5Rjg7WVO(K-uM7`Gl@W48VQH$m!?-?^NVOlDjK;5Q!$17*z+Kmpe!;+b8hvSEelS z#|%*tvF&FW9FOTtjtQc>7XEwrvck;ryn;1l=YHlm86zWaQ=ATPDP>kkWO(6IZzNbm ziQDFXQV8qRam8gBBvm@LmgRX;H~A!u$w@rO%yJcD+qY5dc&Vp@?D2_2vL84N_ThrC zTyz9_j2xd|VMM-lyw?7BWtLbM<#0h!$^QU9UwUIIKbatJop#}h^0_~aZMoX3Q)sZ# zt4k-8AxO%FXL!L?APnO@7#x0n^*chcPUb*lj6?vCj2+f za?Vb0c)$REciyxY3bIG$%`~irNiHr}u#o2@lhY?T{{Zz?QjLx(jTF&ic@pR(O5Svb zb;N;Gj-7jY^HIzkTnSb%Wev5a01&JCaZ~-G!I(e@f#i`yCKz`&ndmtHspBWG$*ImE zm^8vn>}4bL4jV5!P+>ckP#l-v0;)Fbb80rWKrd6M2sa+mS488(YaqC2GT<;TzhKJg^u zh8=2IQW@Gknco%3Ta+ASeFvvK`KvI(zGD@Q0FE}@zCZbB4tV~ge@f9!2~Dyi0?T-# z5y)mwE(Ijyus_eJ{3;l1Ww*HdJ~xviZw;Nrk6(ZP099P`{?#%CNsFdc)uJ0i`yTvv z9{&J@cGgk`cMQmpDKVmx@{HCJk1?a0MVM0FDXol)vC-cdiXrJ~NEq_tGu7uz85#xg<1 zNvR}>3!=uxVIus2NZlbBTS zJ5M?9@A}q>+-@!=cqMnpNRCE}=3lzFAJk*7)~uP?WOj8zvZCQY8$te*^^GnI#~28~ z)S||Vv?okww;&J3s>;$IJ~<=%5V)HW`MCfuW*EuF-bZ{_J6fArD6ZspPb$22g6dm_ zxkhD2j0o+{?iDa{%Z^DWIV5xx{{Ss~)k#&NXI>m&t_P?cIqgrkmK457CPrvi%TqBM zfKq#7Bw+K?y)oWFyyiJ17XxBQa6G*8&JQ4T9nYmtv$`|UvQ5hyiLmVps08gQ*yIuP zG?DIs@@1Lq5;bMARst}~oDq?L*f<8Hb$k{IHjJxB{py}5T*#Kvx}3VA zmWD?2421FsDh5HwI5^|pp;=xgo*@{K?fzV=1M_D*9*3uDl$j@zD}%gE2GtCs1(&{l zv=1OjJSh-)31&wvw`j*seLX9p);1fh(hK4ULjmHz-eDj*>~^mfk-wD#_-uRypHmAOlh%<>PktSDF` z6OIVvuY8Lr6BGu@#v} zqmi4-DKjaJMsm6AMlwE!(wMJ2QOa$lWCe>Bfwro!KI0h~$KzHnnirC0hDDXFnOaC$ zfRU8+J9^;Y^U|ZXG03uAvBOIdR*3;z4@`QIQOOq1KD?hX1RJ8ann5D8u?F)VT!w7@ zJCjnzRbX^z!<8d;#0#z@a;m4(+;VCO zqDYl4t>%`0I1jYQP_EqPw_nftRd`7^FAiJxK|_Z^HxI-Nk8$tsPno!#E~>tSns1t` zE4h)CW&Q7$k1b*BPjJBCao0V#tM+#)a|GdMF4H_E;yfwfWrhzN5DCY(T80QWiAn#^N% zW-JRFbY6qpkLg-4WWy2(R1}S(ONNY(mOuqmnjFSsBozMPmpdj_OdxB1(k^ zJdE@l)Xx#!`{{;Zb`lO6Fnx%~Bfff70c{Ywe@iy1{I!c8WR;k;&BQ)i2=n)tcH_5f({7-G8+8_rk_hI-y9YQ` z9hV)lbN>MAsD9L3O0mLFuJ5x4Awger(0cwATH*%{61?$wlYgt0AX+t-Jd?NY06jT1 z)fqE*w$XKNrnrJRE*aUa8~K)dAJ#9)>j=hmt~$#xnK zv&wd|s+1f%6OJ%R&mH}Kw84-dH(?QezmHKM?B`NS+|ZrjxY>! zHeNl03cbFbl?w@kk&qNLZsaBTBrIS11Rim`KX8pI@wKbhtbsL}|_A5MDb2a2t6 zH1o`nMGR7L8wUiEqd)Hf$^KPIBq++{Qad{08*7Vm0qb)j$g(lxE3|Mu0q8O5S}K=o z5DBro*#7`}4-Be%4&$X&6121VQj~^7V96Y9*RKcCq!%~QJd)epUt15CG1^SA$s+#% z5@dtaWKb4uY-kwfgvPQdUD1p-(leURj^;^TK{P8VLP{v=#Cqp|bN+d)882R0qDNbp z;kUqrE+-N)gVYi*4^!<_Q4#KBRCbO$wq%fPR?SV(q*j1lDJ4_nly_DpHpn>Sb~x+L zKjT*Z#%~fSFE(z9bz?NZuvsv0PkuV*>s0)wEE!XGkewaWNX_g$#%r?BqiMsjhs=$G zHr7DOaqfGMe|qAo?#Y}bEsdQq87-oL)gyR;+UP>D1arvbk7LK@TIn_9&kdvr9Flpv zLn$SmKSAhf{CahxLabHeR=5mE;E3_a8PDrcO=tE=U80b%ar>{EY21B1c%>LibCxo* zX4Q<+ENWnDozX*-TR^PJIUmG80Othy8lO}7{IrdH`R-MhYAJ22k6*2FFvmQS`BBJB zh*yxsK^^}9EdG_PYR?79w|UtNY5TP-Freo+@5iM}ZL;lmxi+6|EQ_^PbVCzH(CrMZ zAn3=bBn*L%?;5>jEYLksu9y{?|zO!*Ft+dby3{4&`BxEY1KF6n~D_LfcyTVPL#+iKBgnNjL z9D)uw`Mc-%eJaKMwr%Esc|s;WX2l_h&O7zv9AwtiF3w3>EaWY2ZqhNjLku!D+{l}Y zFFb>s1JKt(@yE4RIeg4T2_{AZaXj!lgM-K&$E{>V5;DAG!9B5yFeTLM6Yb9!LUP#v zT^-7k8cvVAT(iA5;qlIGoQ!OvxUn;40i9RTxshhtG?pMtIS9D0yc821{j`$ zp0%xSZyPLondVt!&f$adj{g9iayz4Fw$Zg?A;D=8nmIq$G6LH{Kc7+tee14`R$`2; z8)XNUL|_m*VKPkb18j(eBVm>RZe05xZr|k7Wn?kPfZ>a97r6JV zsdX4_k>Pmu+%#pGN*9bDKzRE0&!#F>mf;)8i*T`-e8v&(lreGBccC>>!sMIAi)P5N zxfC!eKZJsP`r!Wng;s`BB+_03zBW=Kfa8(}KmMw#=UwlfNRbw0EXrlh8GjB=2R`@} z4x_o$sk@&uGwa?!pdGXvNg;OP8XD2?M-k+UoTTYTfmklEV z7m>(p_x}Js#~h)q)$_DfBke@Pa{aCSdtWAJiw(v8xi?k!;pTXt!G{07LGz&WQ=(yfPMb} z`u?=0Mj(JDa%05jD=)q=YTyk&{mb~Na$k^{*E!_DM5rI)7w1N zGbvU(#_uH=Rmj^J&vEWL)HNn!2wCh&X)V*s5LnerTZhg{<$Ij{Isw;;+<=24rdmQ# zcMKe${{REhur2=Dmic%~s>s{sY`5;uPfQ&8@ObsD2#JzV?0!{=Rfz-!Ae>{|aC2Hl zqgq(iw2Q%F@}@>!j!wcek?mQrmXB~TY=|-1I2m4l0a`AMs6+b+-yZysgXn{_Pjcco%BoNb$Kr>5Swax#p2)ys@0g73{aLBB&cv$+(mIz>MQ@>Cg_n zt3F$s>21f}OC8D>xK}DyYJ;@%{Kay2am(kdEisY=J4%ogGbrJR9B$*cy>%ki88XYg zCHvc%$!zEAShv$ekgOqG&*qaf#k0EvRW56Y^Xg52iuw_x@&P9k%FPzqsW970Pr~U>`%YFQu{)T#t)iZcS&wA$>t7( zoOKw$`qdXHIU8cr%=71k!Gbkiv4TGCIX!-yeQTe;^Bl66qGPpHWHW^*MsNcE01!RT zt~slkRqTQ{^D!zjw&aPnmK=gBa`R2Km0_AF zJuy~hyAa(pC7o2m%CG@Tbr{d{_p8&-6wt$N(Xfi(unf3TKM$W-MEZiKxav0hBBCv-ZC&`>`#6(`qmZ14GqkyC0S0vw&F5&;EqAa z2abogrbQ(tXsf1Nwz!VsH&-{{XA=si3%k-$`_k`ST=7(L6hq0Y5PZ zehx?7Be@)BJj)tD_Drgy&SYOPqZs*#?f!e#tXf|CMg@z*nBGfP0}UedKA9bjM5)GG zqZ!WZ^DRd6ecjgCSW0C5>lDK?9!Sse41b4e=I&>mqrfPwEQgT0c>Fyp({FSnd!?O` z7?lkoCOY$g2%YY+#dT#APzfzb!1ND#&YX10i|#bWIfAgzBv4=+#%6yt-z7i-CRc?k-jbYKPeF?UrPd$}z;Hkg^tFxX)j4SaAKK z?b1tF@7h?;nJvfmt4A17z*7JpG34^cxZ<}{+?4M3I|Nim0^)W+v9`e)1`NkI7|6#s z1oj6wJt{fU=t3Ib_iq>sRaYU8r@cX^*xcOB3tS|PE(y>%%d1bdO2Ka}f~?BeIaSVhVZlCx zE@WFLgxA{x6;s;!SP7Zo!*Y)(M&xF6TzAIl!~*$C;mhqr}EZgJN-Ma{yK63yhvx4Sa&(*ybb9+k&U;rZ>RdzfQ$ z9MhI~VtURo+!~|k*0_MO0hZ4 zeLCX@*R@Mr%-Rxh*`6tEmo`lgnIc7Y<(6QKUNy+zle80$YVYhdV-yO;RV85?n7(uC zkEKJaXpl#2&kWJb%W|vdWxAXaIp>agarxI7acyyJy;6;eb&gXH%r`h9e%A{}( z(Y3)Go~N9iYqq+)kVO%ma3KV&!6ap6j9}!Rm_JsO2ilHTGulrse#ByJDW<@yoDe@Qo94~eCm$W~UnjGr%WTn;hs>0c52 zaQHVTh;1%)EgsB$y$cCEsP{CB(~t&9_xAR#->)i?O33{eg1EO4mty&6CCdAsff|>F zlkFOsOPg`_g=KkAh}3rJoQ|jZRxX>U-D!}8k4mHhULT{`t zrdVcsc~^2t5lrPB2yno3VcxLB!YTCo&)TxCB6-C}7^|;S1H*nNy1cu1>_>?1p2aQZ zpHTkKQ*QCGAoWY2p6>5?`d2@keuZsJcGs=exM(85r($OptMs zNCVdu!AlV;68CmJyvKzWaYtnqy6bc60pOd>HKm>#TdTWCuY`I`G23NiUx zZ+hzNbhF~MmTf+3X19tdf7jeBamgfkCk(^_c)$aacpULwl(Es5TOW#XR|Hp}-?iCw z)Yz}9Gd>b zZLML|+TTsoR@LpGjj*#?iKe)i{{RB9AmcdUjsVUENC$%Wx%)r-G4W=XDb)NurhTE+ zWNo%;TX^R^I{N-Kr?ZPn$ilTMRBi5C?>~*3-6sxY+!$NoTMkPG$0PaHYr%Cc#PXVD z6Yh`910j7rpIZKczB~T_!90xj7E$;+NRrAs%uKfF3H|2f%C=5;EZh&KEAy+yKe1=U zKMPy5C&O2FPaV{rZOyxt3Z(QPfI$PC4D|q4MDYH}BZe5PJ!ngnTkk##7SCxkle%q& z;aOdkhZ+7<+x3l^Qr(&0V;GT+0aM<+;``v&i}b0M+4QNrm~NUo(6JdLVh>!7J$bHr z{{Z2SipIj4HTp@r_krx$SSEf`k3;G`YU2yo%~XWnx{oflja~sHEZ9eF!vME_wQSlv zp-Lf|MTm?R!hzIRT_=NenCVRWdg580T;F>t3lZ!cQD-S(n3_qDL`Zo@JR)BOkgKra|rX zu7^PQ596&~WVc-s<{Pj`jDK z!9VyW{+g57%i>Fa?JMmzea3sMe=-R+bDu2yhaG_jw|*-rrkUSE2koHbrnK(Q!)*h= zdgq9m3tb~hz0@vNb!i~Bu_i*Nj-Y=&E9$R?{{XSS#IGCLi?;CX=AWktcA4(b7EzpM z1D;y~zjU;p*;hjFpN%ZFeJb5;?IVcCG)Zn2Hc~Lzz{f&IrzXC%)4V&OSn2AP`goDq zKX#V!f~v~c$pB*?{cojn-xC_ISh)PmsmAYTsre)DYxXMCJR@;wf2_rAG${(T%Sfsf zk2&KcliT@M>FVNf%{L)Yj=I`yf8gk^m$eWpv4Nj`1cJd<4T=DU5Y zY4_SM+6R=fNjz4>0#_xD?Djau2c>IVUg=hL!Edfs$?nd{E*cL#R!+tGow?wVlZ@je z)^CiwWBrFXc-7QAE4tt2+_AQHp1fpoE6XpuMs*82m_@zJvFzOhrB#8D_82)VI`ivZ zoLrn!XX|-y2ToXM){@Zb^$!riZqIJo$ND3>02cujx(&Poj;EhrPAkm3dvR{jF}Aym z+@eNqAQLLdBxjI7_v@eW73a5aCaDF*yWGk1FP#e#Fw74b`e4>}fd;3jT3az?Ca!JK=)x;`ktJwNFS$!-9+F01|{Ew;J-Xw&^u*4X$uHwV) zfTNF_zE4{8-2+Oni7rIa-xwwgw%3xtsUtAx%^q+G#s~+Fc{r(j7x3p()`h+OosF%n zrIqwCtTAPicsUr(a-)t;K=0PR_xNS|E^8X@ke6N}QFHt6l%sA{1CfK%894+Bw8v_bN>J=@S^}BVgoq)qa=fXE9h%& zPCJWMw9Ijs!+i3PKp+0T^~~ye65l)tJd!aizW#_lMK^*Fi1J#tD{no;D#?7crfxxE$^S z10?VdudQ>YNo^)&HVY|9RnUo+;7Hv!91L=E$2?#h*F>iqSg1ti=GCQw=GG-x-*wIm z%Exmk=N)_EyInI{jyaxZ2_b04)QFN5MsT?8)c*jJTu!T{P9it9PZ*L3e8`ZX+@tA? zdhuNSjMB7I#WlN2D_yUZF2?f*s2zZ8gZOdYvQSst-gtEB-siSS;tM;G_Gw^yd&G@Z zV3~t5#z{XY1b`0*k6Ps}C5qjR#kTm?;&UYN0kkn*1Dtih7#`JxklhQGc;@mX5HvC) zMy#!ptO&^6mD`M|9Y{INXg;YU*++1ech+|hG?57jC7*CBoGwTQCx-lS%{abOiBpX^ zB1XH?X1Zi+i>q1qXdspR$7bqr(+W;V9f8L<%~*dj*n-UQ&Q+zgxP-S7asXfs3Y_5Q z>N-~z&|m$k-tF8h!J~%aV*&CNaZzb2!Vp0Ma-Z&U=%Ot!iAuCG-s}*Kxd8Gyd`LT6K^Pq@EdA z{v&U{K6`y>sc*M}3njR_`Iadn$r2VhQb#15am92xJgq*L6a#O~&~;O!=v zl&MKGp?|O&cC`&KyI>Y5{>hl+UUEz4A-Z8eJ7BScXJd+hIB&0~qgTfJx zPriC_SN_X9lbIrw)zUJ;2EkTb^c;2I@=ayxlN)=Rg*&H?b}gM}v;C!oeY zxHZ+On@tScdmZ7okqnSbPnk4%+zvbQ-`25pD@pXSE+d{siru4Igh0SXhxo9dmQXTy z9l5TJbvr+|PL{^$r;Mq$j_w6k-RMv;$m5Zorloyp?WAe!uBWqPEUPWCWsob3HzS-7 zNct1nmC_VtW@lSS%wUjR*#nI&L$oOS2d+MD=J zB>m^9p*^OVeRT(uYc$h1CB&+#8c#vja6YHpVzZ~S@|k3}hA5eECANw+RbVs5001BU zzpX<)rEwm~=Cl?9&J_mV&kZ2}U@^uv?mU2d5l>mJ1o&BEX1R!YzGIPv1Jp6r8mw*`@p%!PCK^zDZ6rFgG>+e7yR^7if|5BBt_fvj%9RJJXFOLws%Y^tq<4vZ z^2E%B$hz)OMgiN<^ZZBG(!P|5G^@F7t*v6_Tzv9Ka6=w>_8o_{R=v=yG>E3N(Zrg4 zw6X1)D{0wOt7J5Ml1kv?2eBfzg(`IYLZqU)A0KLFS(@rtWQsP56j6X99#~P6i~+kH zPjk*rb4}5&X11C_;7dHViyKJbZH@qUWM}S@NEsZSGsSw3ihL)h+1y5{6pM3nJN>0R zvKlY|F$Ek33=br8k?qd~Fw?A^e9t6KWDJo!YRs~B1HJ|`&rW|GT$E9zCmvmoMY0kY zN7{bIXIOqq8*=7JBOI)b7!}DRs0w;0IOei-9UAaAp3!{k5ANfP{KZ@RpV!vAPYGS= zt8)|FI+7D?jVqRnu}%)r&R3J3di1UPyNDP&eWH7^BEXJf3L+E6+zgIM>S{T?rOcdc z%uf&L(OYRTPdrT=rUvsOF_PP|e?Bq(MRNM1Phs}0O=eX4DrH_(1~3ozf%NySnYGKv z?``arnp8ws-Ih|qH7$?=_T-$Jw zo!5xfVw^3^C8WaJ+&E`dlRW1K<{saza@wWb=j`%LBCAe~yg*8nUYYg56@g`K6j9t+ zUc+}0ir?)PDJ8g7Do+?-bI9Za>&IH|G)*lvPcKlobue3DO1S}>g5PxWk+k$5UevED ziE47H&znL$4_>%4#b);R`(tp@U9=9cl^sBkjij880nc1?t3D;Yj`{?A!14a_MG0@Q zt;rbLTdR8Vc*)|EP}E?!G3l13^vbtCHk4&DTe}?X*n~O1ldc2j$#A=Yo3l&NJ5)k28hWL(-uKQ6qQ4o)`ONo$b7CCXV*obdM~n7!jw; z2;G3Bp5v3#oQk(?;R6)1F2;&KwE2cINLI!G9)|-wpIYDeeRX7H-1A1#Mp;%h18j;v zgbz@2Ubl6oMRbrnE%tcgg}!5eHxrznp#HVlN-Cr|j%w~yt8%l(JY8iYK@2yp*1}6> z+F-W~8bOmBcqCvF04KL34%NqaYDbUAlIA7ScHcC&mfCF1A}&r|G?Bq#xZp7v$6=cK z1IAihHw$X39`Cb9AD##!1BGVKZhuqnUO922%cg3#8k)-*X|`7)MH6j1!h%64atPq( zIUc=hPFAg{+d^=7XA|2kb$RECNTC802s0QVl&`VlIrgb^y)CX`k&Bq+S%!Ec3)kz= zezn9|>X#5)TW@1@B~{FEs4EC;u)>USp2EGOMR;YlhVa0#3!u$8356q|By}8d*1B&O z>ToEy$bt#)tnGJCaSK2LMk3@gs3Q&21RS1+JRfY9(q1TrTWJ;5U9x3=EGqTmjC%1` zC;KJb3|r)dUA&^qFs;xZaakIL#l^IDt0WG#kQ7z8g$qV{V4QU1^{kxL>|ZZ2-dSCl zVtd6$6G)7&EX8CD**`Gr-?`?I@9n{1B%%q3ja>i&LH)kjw(gMj9=WWo0`eKHt*shJ z<4vrf5Ca(-oSx_D@9$fUr^7Rkk&DJo^7z}kpdP0HXP;43&-aAaE4B77+uobmA&Emk z7amsbjgI90e0pNFbxUZjZFaP%AIX!2s>A2n`#+vSVo}&K%VK7AuDu7(ZGMibL zkO9d9B}wE1(>}Q;ptMN*%V^ajg!8^goEB{J$n10ede%$H9n>w2p?u^nUBL|8kl62! zP&li$S0!T&AytqTW|_zgM{-Z68Lm{L&J|Lz+CsOMazQNd$8`+&`#gxrCQtDe$11~* zl>K{*-4OYSw3dk^cX-us2*!*&!H#MwXNFX z?WBs{NMv6$v|y6T%f>pc811VsLz`%)wbzoVmBA$lb?KNKmBU> z_r$X5?>U|XxYTcMXOc_ASb&kHEyAhmCRYb>$0r!*Pt`s;xM(!h5U%(of^RNJ0cg;t z5(3!5kWWL;UrPAo>erCZs3XB7=^ML5;~=m-IjvigS*s8SVz8yrcy}bKN#;CBBKfEftjsgC;uVL`+rq;K%w(2EuBW_nJ zS$g;EIX|bhdA+Hz^UPu5jzU{4A{GeVx~FLEuwM(Qa$Q`hB)N%vP&$A5pW8!obpd&nzM3DOe0cU z?QTMys-p|kao;}w0G(^C%_A0>T03bcM`*Gh61fY|=AP_{6jAS9hs}7TBr{}=dFnY| z!}F3mn~P{&Ad%Eg0hB2q6&dUF=Bp~KmlN6$$oT>?z=62))b$uWy=aB*D@#(r-eSSH z+iWl+NhDmTBn_YsQ1N6H8z$#mpQ2adyGLAm=>(V2+%6R&>61+>$0AGX206 zRIf%nbLs2OeQC_@Nl&y+#yHE|U!hhkG6+zlW1fWj@mjX7V7Mu&Pv*deyLZKt6f zzLhD(^&N_$D9T&Puq5*cn{wQYs}YhL90Eb-(;#u$uaMGP!wtwjbFfQhDt=Y#$F@#? z{br`L()AgSW3kr&e4Tq$0PWG zQhhncp{~N;OTbcNS0PzUjJX)xaDOaxtw?R*RPw&fDv07AG>)W6Amcn^9P@+i=}zq4 zF7e#uAkZKMUiS|mj4B9@R4_Rto=339rD^{FWLjA{cZFqP3E2xTARdj|@U7IhM}gAj zICsmRDP%@FTks?50jse#|a|}$2j9T>(8Y`wPeZ3vz55g5ugh06+|k0 zz`Dw1HjTQbdv#lWG>+ybi-1zt2jvLd9<4 zKm@3VB;%*A{{XAk-m*%}=aZ90be7*JOS9&=m&}mFqDdM|{J_8Q1IJ%dd($qUX=4&b z0+%DpCk2!YjD6$QuExl*$1WY&qbtEx0zgT?=aK9Fb4;ztg$qVWnkL;6wsx+41!%6= zMlB73&TD&R^N5aBcEFBc!JFIEd()MbB}r~AMaKnOd1e^wcsZ+W<-W-q%bC+^rsM-? z9Da28?cRSrLu~WEm-4JER!jri2ORtRd(!Gmnz-4bCH_cahBB+=Mj5t*^&_ak`qM4r zX&j{K33(+O3`iGo9^ErmCCWl3P2@U(<+1sdhi>(1J9L%PY_{<-M!TXw+ulLc=coSw ztKN&VHBELPTS;b+;7J-rO0%DpiylV=^PYr`nW(3;niY+9la^KJTc7iq(@@IN?H*{` z^BfgEym8H0hB*{8PRhg*%bbnM2d}O_I?8RPQcbfN?PWGh5xlt|Wy1m0y?8wbsQl{e z5z1L5owDUH9yI_1>U#FbtFqao=&Bf)rHt;_#Tb1E!5_|~TX=2bB2(qT04&l?ImldO zOaRN*AC)Ab@dF5e5h2~XgPz~xTFiz?6+qgX4j&l- zzZ!bP;fMw?l=&J&-nsgER_R=)qBG;nv7$IC_Nwx!atJ>@4%RXiQR+w?c+VcR@3YCU2@_zFP}2n?EW^};*MZMHDP%q-A9P!kTehplV9kV{cBO;*EOqi~9GW_bv+Ktz&4(w0#P zE491e3}-z~GvB5~T6rUKj}Q@wW7@IsD-y~9CxHqhH2fzcChYk%yz3| zBQ5L);Yrzc>Kc73pT~Xd|>1H)|$YJ8OGTdChskq<|nAmf3KxX&_n`C+e;#i ztTGEXzc}w%&m<`AGQk{j&Z@FW8t!HTu|C}^HyA|S&GMHSk~C)8uOf2j8yE!r?)^V3 z{&j^d>~8x8V`P*S41QKq-2334&X(r=13E5Pa1Y--Hx$Q|PB@dXPUvl6BxpChl{{SzoTzI^N1#_?r5TmD{`hSgQ zJ1CRMC|tYlVt{~1>CaA`>uB90SSz$xjUGg469aAl^Ekl#dQ-~~rKLNhXCESvLa#

    @b7Rxn8^+7(1(D=MD7bHNAv=B~*ZjiYJgK@=pJ6nw8E9s;j! zeNO|P_^Ok#8DffQ8B$keX(Dn6_5>W`jMKYETxyeup|@9-=2H}LD`GVpi#KfNws^>_ zQ!d#It^2|ld1Q0*f1mTsI$NmrT!|aZRhVuUNrfxuGC9Xwo+^>LkIYyBLY{WmV(GZA zBOQq2sPw7Sxl~CGcWBDa_Ys+8;#*Qm?!JVxm>oX45m1y zB*XS%(n%DeHfG08F@sAz&dC1L8~KD2zY-j`9Z$HN$T)NXdL>I&>YA1C~>Eu6UZJ%`X#Qe49fvNqOf7~qv+ zyIbj;Ry$oas+gm3CfN_&V9GfByY&^7d4DN)%wA$_{{UF6hE~sE+RImR(5_ z+`^6)NeKh9XVdbmce!|6S=sVsxZ1)^7sDMFwS zqrFLMb@n+9$k;_Cy2j}ujm$yL;CaS)AdcTsE0Tg~Ad_U~IbULhkw)fVPfy1cviB;{ zG_gXzx*3TRCw4f%&VIc5R!z2HR$gY>+}sHwl68-BouEj8#&eO7cs;t-gnFc^g3{fV zNednB$Dtj&3>xCC?#$BSR&gw$iAE)`NAfkVYchiiDMZ|#Jm(+)d!MKDsd8v=QD)aZ zeY)H#EW$iC$J`IovHH`XmweJhsxS+D@qo%09!I_^f(N-Iv#=3v0#J7|b^dibTw6wG zXc~C-#_1evMi`z6By;P4J2B5p)8>@A1f!vCuV9idDFY;JGOMaEEX&`w89$+_x}DSv zWmwZ=4pk#w0nY$;>FZhRcvX^2C9}GH*hwKt$T%mc?UT=1j^$%4@tv!3m}Wg$!Tmov z&S|p*?90|kAf2RDVU}4gWfAZXPI1>G11HI+hJU>2Ll=8bJsn;3ea2FZe9nSN_k3F6hAfxKK(h(5rvH%NrIOxA1i(CS+#w8I#_ut5 zK2_l0p1D1}`l<(OkWqwxWBIqVV2IVZ93ICNV^VW9nlOo7TrZz;5ajTFP;xPxf^sSn zMa~VJyv!LME%7K-JHBJ{43mNB&1YERTge!yC_oXUoSoeBnz1dsVhfoaEhb3rBg_Pr z!wx|l^Ml{%NvGVRHr9<7C*@K;ZP`5jwMJ2oylTy2vPPSb$>p~NfFX$eD;6YZBuM3W zU{L#&(@VDO2y#mO=^xBlq8$8Im-_Z>Gl#^K@%iCcg$L4Ayr3GPCXAyWYn64s>343<}{Y_ zZdvvdhR;Gfj=g>Brd5V`&BfcSjg78K>HP(eJF<$`8 zmN7s`3!Vojr%})6Uufz!>2VQ1Yl6ymla{(xWo7gLbD#6xxkuh0UR>2F-J={{290F7pngX9zee%Y5?^T1=z4ym_DC)Wg6=~C z#-&dxz!Jn`AxXg?4su0&mEymLI_9KW=JM8iYw0ACNX)Y^kVrqg0mBCCgOi+h75jbT zZw=W*qVDP_;k2Ds&1FT5h2Ud2?do&ZzCrQN!fz4E^4xunQw$evC9d2SU~|-uyfMfJ zjE}~?KNURFEyjN4igESW_`G&Q4{h$n>#_Ky@h8JJ*IE_iHwVwTv$&1o-1!S4w_ZB; z!1c$aeA(f7A=3O^ac_L>6Wz@tM#fyi_st&$!@7gP$s}MC`gX5N@b%7*;te`k z?q!Bex`*d*+Izv0NvtXQZLW9)f3OOeg^e@8S2whF#*e90SIKIwgjh@(vT1hd3%Jl@F z!#|%L;jJpt9aGM}y}5gLA~SAm(%v}K4Y)pE-&P!w-!VDQdiw{#+CG7z=um%W!v&SB zs@_$MDTGo^cXt4vYU6l+-M)v|wK&j>TG07Y9|G#fQifSx@+)+^n&BoPf!nx{ySX?3 z41S#}xu3(y;uxm7mhNkt+uNTmdF5ioKpDtm^JhK!*V0#7b*-JGvs{G60B2}9$F@4wP^Zg1&!o%d-97DZ zLYArU(L@ppb&SbyimdbEOsG8d&JXMP*RyFq5A^>42ly3QIDW%-9AT2~^afT@oE^T0 zpInZZ#XH3M&X?gm8q(uZn%d&}2N{A4GWl)BXDISrW3NdN#2M^V8%kzTe6GQ>ySXQ7A9E8^cIX6&A)*S`q-Lv40`-*+9n zc87D@Ps+EJM^-`uA<1qJJw0o8#2WpnyL5_CI^E7h2-0N8Pb3b$gyYax$X)>PKBsfx zfg~EF7W%a9C))1yL}{9FoZ|xraqE-ldRMA=JZk#?0Eunw!?>`pv)^-++_Ezs$M|q@ z&rWe)QH7$T9n7m_lADkn@Ww^M8{NuUX$u@F&UobY>413eP(7EGX9V`vX$Aapf5+mn54R){)Pe}X>7JhT zh4Ev@noJsAl_FWho_x@|-mC$pSXhkngU3Vo16`(_;tdl207r^jByCEMqUu*osjTqoS8w(p%AQ$}EQU4>yRLXDanqsqubKR3sAxJB{F-Km4e!~F#GmO> zN~IbG;4ab1wg)35V2pG*`kj0+r``##uJ1to&&_EIviXF8o<|^o-=_!Kzdimf_=)^E zuIg6y*6jp#!PzXXLi~;n7oK-6(UF{WKKb)$SLCU@!bej*ctdL6_43<#b#2I6Z z43$DUe8+YVy?PPE^IORCDd2H#r!|hQ^7Pu?TIsS{+!TV;E?@FRwssV!`; z^-Xe7Jlch|rInzXc;LEt)t4Xv@{yc#*1W9zP}C>!4Y<@AFFOj;+)0^4&72b3M`BMk z(RjvDty-?B0M!IiS{%NIshf6I=vQ)ska^&W=yl|m!}y-`XjhAjWVh?MzCZDfyF9mc z8WytAT3NF!ux>J3Zd_!u{nD%s0O~MLdig6-@R!7Wd;3FGwA5}=(HydQdW%JZ4j!OX)X0P zNcRT$zEIzI@z@{Myqsl5-)kL>nj@m-IKv^03{@3knBJ4H7}S&8z&_1pX> z8Rws_E3)_n;{$Q8#bc=2M{tH% zn|7)^v_NHe_aF*z&QxF)835y;HOFaR2fPQS-^1croaup}^Jks~5w*VKl6rtK!RHm? z!!Y)BAGCUU9_CfURozumb(~V^X4Cvp*?6$%w-Lu3zN-$9RX=~`!a$8l`LI+Rjkw^7 z`Fq6L>S?gbf=h`bXk1d#g4tY2v*P!^`^FXrIMZTY^Nv{RAEj+rA5wf;; z`BAVz13BZK+-9C)@Slo&D|2sf)>hLMX0v$M0ki~7T4g~U2nI#e6_Wk?P&SrxyLF;01tm!`bXhLrmKrmt|~B!ySq84)Qs^T z!`+@ktN5L@Y3*C=(AikrZ@8My*Lf0{LE6u_kQj6T_8bb`)NU8-x^3KcuQF;8EQ+u) zv5!0*-Nzhr&mi=vAn+aDtzjmkVGNeBCB&OvTZL`$_QLh)kWaWAS8w4<5Nf7I?DFvsyP9jl_ADw2keW9dDOCr|fk?R2@9qg(i&SzC0|Y_y-T z!d5G2EUmnk;|c)^2xcR{Qgfb7b{ZbDaiHEdpW-0K?7PV%G9t(2t7TC}Fj;ZVTe&@e ztD1JNpi33x5xv!oi`*<$&=^I#G$fE4D#etXagKTF4SEK%;O!sAaJzk=+g%;MXWI~t z7?fiKw_Y*d)RJhGWZJsXo^Bz^ob6Jbqv&SdU1>V~;`vviSBxZfF~&HKKsf`~o^k7% z?d@$ey)Q|cTew#4XyacZaTrze2^k#o#(C}NNano0^WjH{JRy1Zs|&Z*b8hQ9t9hGG zVm9DslgK`m)WbQs&|tE>lH$(y%Mv^jf2__A1RNE~#&gK@t=fX5oMoZqoZ@7Ywd5k%N*lI%lUf(JrB@c#_`Y($_@?S(O$$5ReHb+U@rc zDap$y$nHSLdhsnXA06|T(zPuj-r<}2<}+LZp(QBVOy^?NykVv4Qj4n%Cf?2{ z{J3U<;iR~lO!Z`MxJN=)BZ1uJz0bnFJk!m*mN#A>itkXG)T3U=r)+Z&aLfV8Ba8q$ zbn9Ov_{YcE*Y=dRT4tXf*kow@k0cGJJuulIjANdCdej;h#v!9!T*a%wEK|wl%Wvf( z$sR{gSxM=~uU@=Xbt3E2S|d-XO12N1mtQN~`ikYPwV1Cy+u)sA8Imxz`kdD=m|9Hy z*j3A5ft(y3M_gB)&ERhg-d#%!ziGCD?$G&>IOTh)C^#|v-A_;n>(aWP4}4#PR<<{Z zsoGDa5gQv@VYmsDGL67vBoan($2mDByK6YSF|RB~QX#b~=~Y@W5HYHO)Sq6Rx#qOP z{bGXbzpm%WRLn7WO0StUZ&&y;$nJbQsCYUXy=HsgG7CuKNiD435Qva)6?2Bd@LwE} zoboEignlPTZ{JT1b0k`n`>lYKChjris2xuP^ZDYv*I4ijclL3?r_O{&5suCYL1n@9 z7|9;hz$d}mi&%Wiwzg=#^d3V7bzX!K!Cdpf_VpF$VXM)pAKz+qQOK5NJJ@9T>I9pojIq=Yk8cL%qY(BPnmh>c93|k+C{vI7Pk#@qBWHA%A=g~!nRLQ&%IF^ zJ@%t{J=}q3xSrriJ;9A~+zwc-GT9m2c_ieT=&y9&4@na?qo7)(%F1ozx`4C74hp($ zIl=i@6Q0Jld?z$h3*WQL9E!^rg7V-Jp_H?oFrua8m65hcDo#pHg4Xa0F(89Y} zNg_ojBq%u`f$Dwh3Y1ip?0I?jE@hU_nR96SpQ4(5#J84=8aIw8fOy|_QbUhi^YlKo zeHP}~=9OjL7iAnMA%{;<&wqO3{1fK4hwWjwxD&H4?#v{go1Qr%q2t@0wcA{mislBM zWeIK+?sK_u+_$f;E8y$hR+fkJ1zH@HTt=yI&I3gN5{D7S+T547A8`%tNe5My{(WtH=KYi&SNJ( zD`(_wz;ZHikKUU(h3`gW=pK5SPI#*s}t;ly!A00o5qPxtt)A+B$Tr|JgplRa=VJQPq{yh zQ5lxye)CIk<#PE0b}}*UJx8atVC5my=Dx<%(#V2n8Zy&G65>>kZrIn3M>sh=)Gcfp z)+INk=b4ud$V_TE$vEdAo4fTtgIKnMVcAI&yKIG0zmOcL;(uhit8I zOp73Im&?!H1CBw+C-SL;B-xEL`S&W7`$X_MM9`EHGQ%vu1GErWka6>J%BP;3W~aIr zGAOu0%9kiH2|HDQ>7F?2`qP6K-#p+XQgIMKcJ3WNDs+jcNYO2m+Q(?oktmu2BQk^h zCm<_iXFi$ru7yuSxjUkpEQ>O+wuL7|U$jSUF`5-+>xRY%&wlxiVOLZ{Wl7{&cM^TE)N#~P;3%eMO`)ybaUoO5$6yCOxvEh} z#?!v$fwGOExR}X2m&r7KRj9WO3rGA;(q|!ozzd8XNjV(UylEg;5p43sz$uTHb7S*3 z^{5=rxTG#6je@tGD;UEQ&fl9D?g{+5)X>8f!wY4B?G_>=5G~uzs2Q?VS&2J)4EE_w ztqi%B+AkZ%YeHR}r&z%a#Y&bBvCxLtWayOF>qFi*?@$9xacrD1F?l!=`L zVr7!sX!4kK2a%kN5!VMjGgZWkda%Pi%$6>toA(h0jE%WfJG*uybI%pa?>DLl$xESX z&0y4%bZ&_#w-4pqs8ubFrCT1I4Me+A$~$eOMxm2rSlbu`k+-%7w-sJnc6lO|%OnCw z)(H++vg4ni&Uo~#TZobE?Cs2mvOyaFRxmcP&j9Bnbn98W#Mws1aGF*|xA|iMKxnWx zV1tGu(2>@pKQwYhJXW$8zz=WbgOiRA1E|QQk`jh1i6;!QTY(EAf-RU^8!VI)$S z?XARYWVqNQSuyui42`FE-hOyJ4l!Cg>DZMkvKClEtlm`8G5KbWFk?~&aC!nqe!jfa z*Ak0R(}*JrWj~iZZZ|B485lheQOL;Rri;shDU5R5J4#n%4>@Fv9=IJl=iJjS;aQ^n z@MX7I^AIOKb1P#V#^KkR%XtwWi((ihVw+`&87^kX41}m-k@vHaj=8M~BAibIF!zI)*2CAELWS>_A!y@*QzJ5@zFMCxSaHyC)b;%82@!)pmgYq= zN49p~jJK!IjMl10J27~Ogc#YTGb!4vPe6L(9Okn22a(_}yel?BoQV%$J^lUbrp_^B z-KJTTBvD(Sid$48LYS5W4B%8{R zj6|3XwMfPXwnllW#nAr%MR_u<6s?jF7G>t6YnypYlgK3UE#^=bI9fvLPCInR2PclS z;;e-CbA)wY-Nft}L~ITadt;8`wWTRGc2Sj*x*xq>`rO=oirP5PD7%$TV;T9k5ucYB z&If9i_27_6<%r!Qk#XeU62Ho+9LXC1t#J}UcWi?V8)W2e$pybwi(93S=2Am*f(RUpW3SSXq_fKuQlp`Y z5w(T_gWZp{T)efP5k#S8nhnYRj}Tl&dh)sJfzNu%Ev9D(H!a6m&lJGCF}kTLw+3V? ztAW&U^Kg2KipEG@=H@s{&YY^x454=8IVbsGcluR09sbyc89`K2<%dAnVbdVw5Kpi5 ztIWY3J&F+9#UyOwm2KRSp1Ag|k7(BB-pq>_2ubL)(c%Bv(X zotk_GYnd4jottrpJQvWi=6q2iI1nB*~2oN@H-DQ%^Zu2Et{ z7Lpb7XOs}Y0B`{5&vJb$E?C?-EQx1|);PgZOoXo8r*m#RcI}$5mg{Q_@W(pOIW6XF zm&`!i^gMzy+)yGDJQInaUpr_JxjtUdNXf=euWZvTXIKeH;)*y+WJa+60IN=T9)lRI zAte?$E23D9&y&9LX&lLgfm%?^t@!g%&W`N1vBM)xc_R7VLT4wS{CNE;cZw;cfpal! z+<}DzpW##Aj2!;}g)O`f<&;_Fl_Q+U;1XAG$Qkz;$K&r+?Vw~-n%;Nwt!B8yattm& z+`xXh;-|NR{Se17-r)Z1ZaIyYudxIkop_|Sc&-_tl!mysk%F9-ARpyYgEUe}6QVy1 z%IMvzSWf#7nU%%EPbwrMcyPaHkfuDc3F+IXfAGn%3fiE)i6iowX%((7c7^j84y@hI z02%ZZEFueAc$BM2KG_-7ag24q{OR$?hEcr(MS;0g?HK<69CxQFHYckQ-uL}XI+e}6 zo(PiOCIuXlf5)|0Eb**ZaNoNsh^PQ#+pl~N=Sdh6nP!3}p4!xY@@Q0;);#f$Gu+^x zS`Uqmz(*J-Tt4 zd->8&(ndRCqgdovTr_}6=rZw60eTNoXGDsn>_`OUnw))zZvV!K9h^5+@%{{RZj zq{OaCJ*!B{>a0oHu!Z?blafg}9^49SaCtlh{;|#G!MWyNs@0 zBPrbH+dL^fJ5;N41*4=(1e;}7^I)1y(nfm{e!u4w)sXB~k|@_I%x(-$a3PowuZ~%` z!CYs7-=5Uxb&}TQr63uUENsBDDbHRhs4eZ@R*3|DWGW66vXBn|4nRDfc*yTnqgS}N z0t=~Pe=YVZ;ah3ouOq)B6sDxno2M&oSzS3}@<#MPmoL1DK3sZ^ryP6!w9wE^9n4WQ zk-<6@Ih3nl{oos@{{ZXzRk%Z~y2Pxqg;onQ=YlNP$P{-Ne2g- zm^^sgRHFpkB;E?J>5L9R7$=_Cs_`*IHv+z8+nUFxXuEc{K0Z?dHrjtd(kbfbW^xkN~tosu&A9dM@}UCSP9sM}dt5urPr zwi#IT00Yk*PJf*wc5^vK2`G8gg_x--G3)*n6cVXlKH@247Vg`iOe@F%=n3PI-ldA{ zPdZA;Bzuv9ub4uClhgx(f529CQ_z}<#6m_lOC7?7m90qgV}LAUXu#=!4@2sD^UXJ9 zys-IG#S=0E=1qbN9_04?s=^hRtW6>YjDG4PFy76QaG>%>Q~v<#s@tH7NSa8lN z;zlFRQb|8E0s-d(9D8w9N^+UeOIqqrBA!Ykjq;kPEz*bo0A23pR&rWgLrhG)U`;ZA^0IA&I$WBkq_#9vi za1Jxgb@Hoh6)Hvud~wSFRJ)ABa^Rh=rEm`;8SRW5)_ly??L3B62)lQgTWYB8bLlSS=8WQI^>mBrbXYPb3bU(%Yi4ktRI&l#m|;F$bZ~2R@aI)S`1rvY7%o8{m)5 zn$@KRUBL?SCqs@#Kx2gEtxV?M#p*xMvC@lHy;W(T?o8LA$WxFsZ2*c;MY5NQSbHksRXxCNpPyp zkUA*B%0Q6w+t?Gy^{28x2vlwHq@OyKz{YvO=Bmh5WZX+gv8!wig~KrzC%M4j4xG@d z&9U>_p>8-!BJ2#Uk+7~ak59&{sG9|F5zCO|9Os@YS&6lh-^;p&<bpkU!lWMGcJH$$I6MDU>d zJ46HWL&i8ec|7OW{QA`6Y;hw-k}hX;kjp3_lh4XMx&12R4XB~k5P~IGxg(EW*dYG^ zPo*Uore`;KBR)Gtc{enlyNx$05EL;Vr}_7%$1o8^0dxDgxIXC-m$!=B%rKI!0!*h6a4FPaNAo3Uu)lkTfv zV<2SXpIVYexLM`poKts?Ff zd8Hs(&}=Z=CzcRPCK~y%W#@Y~W&H;2SBuv;JFc>&F_s?pv6Ftmf zh;?ThB7-}fvA`o47(Itxl*f16@WUu=vF>>lSSt?WoOCC>N+RBbZH-hQ^3hJyw;j5E zm6Y|7ytz3>v=KBQypue!fU-*?4ZkVK;0y!TBz62L(L;6Q5dl=1a?1(1i+pNvki>9E z&JF?R6%=Af7HqJRIixJ{f(IY{Y*nZm$vYuzCB%a=O_%b)IUp0$2OT>Mbg0!clC0EG zQRI;f_Nz1^M3Fq$cC$)ZRe@mK4Xnq3?fB6sxDXQZZR@kjU|273eFt6-^{e+nFFZnk z{h~Ab*8?QS&p)3z_NtS>l zim0xILXqDijz&K(dUUP~k+hMAgNA6+aZ*0Lk4n81%siwL#VdK+P{@kQyCiZkgMvDK z6&1vb05L_ocqB+8l;%Uh}gL;c+0vN;(Z z-nCFhwCO9cAR7h9ncd@m-n_E6%ou0W9dXq2%`cr4(=Et~BuNgzY?HT_laun~MkcG5O$jsWw2Xh*w~S60n1U0|I&DvGlE$fc>0X(8rz~ zL(XZe%npGHOXo<-<)2UhJB~T+=~_0i+a;tQylE~Vb`hzJ7}OF=0DAT381xQCzJO^ zKbiMFl}_q298o(=vHtN_aT#V~&=2QQxs0O~64a8-2IQDTqEZ~k4ak@u!~udckH_Ah z_IYmebd7ExfPC@Gb`YrR@`Lxg@#-okfGxQzEONX|o7fG-RgN-olZ?>8m0?Ksmyi+@ z8-lRTIPcH&sGD~*rwfmbE$&Hz^s3?{=G>jE$>HO)kg^t~&mEB%Xkr@u=4n}zHYE-#Sk7nXZEzC%} z@I;DH31CZO)|uo)vlMyN6`~kNT&ThH=N$h4FKSqTm&=s12^Xq4Ac|}@lFPf4GRGnE z-H+Xj)wz?%t+`4Eya9tj`>9!xs* z`9vzt=gx342OiwW_XP)-l)(vy2XmkHbFA?5ZJLW2QEpkPn0Ii!km#iNnT&Jb;o!WD}4JaPGd zT5}1EL9L=@iBdO`VHx0)kDItXx$b@Hij=G@u}K^GlCPR1MR<}tDQ-x|B;fJi+M6^@ z9I`#ikR^wrzF2eDuLqi%Y17R`MBc+00|jF~r_^@EW=p7B6jL&&QFKH>ak-oMk;l@h zK{FJl*>{Mq7YdO!Bb9k1GMO?! z;Ac4Nk}=PvF(4?4o??O@Se{6JTXvQ;E9Vlju4D>H&jgI)rB5}ajVz+_+IaVF z*xqncjPSszIZ`E&Dq&TvN_+|?ZN zZ8Dw1!)}fqMq!oNBd9)HeKxKD;GRx%&UvCHifyXzG_axA$>s%py>O?Tb8MiZJkWO+s z9AJMs%3F?gBPF3M?Gi$vV*#IP$lE|HN2$kND$_|F;#(Nq;}-Fq<!auO+>r+sa{R{{Z9S7GaklMo1^`WFGue|ZzC1eA32L0bKBN)NQ)0%C?+eL1&{f_2)sQyzFGA`*Cu^Ayj_xgHO`>Ex- z^Pciy_L-FLcPDrFlj=`eTUWJ`FtFdP%uLalE+&r)3t*0eB&h40XY|b6>4irTmhiht z`?h#4=G;kdlr(t50^I>1;~n`GDy(tH5oapGHjQOT2vsNVXBi|Bk;nf4SjKZWaxNch zE>d7d;&aY=^`we5MreLRFWFaWsXMctNj&5c&~ekPM3Q@xId!mM$QN$0oHt_YxcjMB2m z3NGk@3cE)_7p8ss(HeFlnw7odDn`}JthVq)DyVJ3;&B?Nz|Ia1Pf`bS#b}0-b$3Tg zbLA{xsQaysbJHW&@v89L%ekRo580xNZrclMUoPu%)`GNKPYn|N~Ndu&b zb2IEQGx==sLWPxbdSv8~1_n>mn$#0{Nh2&vGdldq8wHT(Cy(){dahSuTZHE#tUUnnfulcSJ)K zR=~$2q5OZHL*)p}mnA@jgnn@?ow?&99kW;Oz_yM(j3kL2LMkri&mFLT&$UoV2ino6 zT*0-K;wo^;c?Z~oT{bY2V{RguM$`v$723<4t)E}R{P9-Adt+2>rJ*Hb*mkaQg3anN zS61UsOBtT#TeM=}*~8?kL*;M-*=)Tj5zDyr2@&{wm zrNZp0ZpexWVw=c~WsW4YEy+Sl4(OzGAoI^1dzz6Wl_iquSmxOrKtbmyR*|vSkOw_! z?GnTp${@9dMKY*tGcN#~;{!gpKcz!5v``2pk^IwetN=Msr19(29<`Ouj%Lw*Lk7_* zT%WYGWv(#^*&LY27&yoW0Fm6Bbf*S@Du%vDr<3l6k+(6&LG-4COQ{;x+BQ~L)j-{q zlb(Qe&T8C|OK%*vUQ48+FtT|zr(|*PGF$jgc8^n&&#iOosg$)U$K}q3X^!+ER7Wt| zmM1FPPdOOt{vwI(?g@n?ihFm7Tq;VXSmf|==tm-$sQy%!M44Sc!8lUcHFjv_4$Bmh z!n4M^i%FG{#&(<@<0O7HIyQ6jJDHNrpCgGUx!%Z*iaRsqgKRS~ANWtV{*9&B%%((nABUnB0MkwgBn|Pqjm6QWm!4ZMt^G zc?#VJ9Y#5(O&cxDcM=&0dE{qy`L{4R=jv%UWD~O@dnH*?aMAqrU+F2&@W?v`E21o<3=RN($JPNN9Jl4+l502#c(#He1UC%0eoih5j2C8W{M97ZksqLBezsg9oYGEV1R z2(DtPT>jX{xRo-r$7uoYB= z&m{1Eo~NZY3n4AeEbWU+b1`g2q_Z|L&~@N`f~CoG7&s<8h=L(gy`6^U$0hrp{=G{b z!u_E6_bC)e3cE=lQpEaa1pXCiOn6w+yLfKpjK)+lugI~Sn8@Ss zKD8XvDo&fEjxr*SGXWvCGk!kY|%1G z<%q3gj|p#Y99I{&3O2<7ZO7}3kFWUEXk?NLnFLcRqAGy90ga^3Iqq@O^Q|bPGCUmsXo|wm_S(R}=tJp5H<{eJV-B^1!nsS10WE zMQ(4WaM90^(EuQZ9Z5MHj8QaSXxthyg|_T0HnI23I#pb*bjqAYMHbK`E%UBeV;}|3 z9DX#(LAbarI;WKsO3}Nva@{fi0PFUtRm5`RDh3-Ple>Y6RA#}G5-*yBh#Lkn0qSv_ z9=HeBrD)yQmW0-_+J#qO`^3Mz3G)U%fYa{wEW&8v2^^9VfygYY@A-5-)lW%!De2g1Auww6-!97mQj4fHmAvr&z2<4 z=vd$!4yPaES|~14id7#mYG1OOcDS{ZQ+J6@VUEF@YLW)#E0VZ480qtK zQpRoFZ)e!i8KMjesmW}5br?Ri0?d+69mTSJoGBo~B%y-=!8zzdazN{XGsvgRT2zzE z+ZUeaY+*MAZrr7`=kjSnfkdn$U zN~k}~P_xewj6mwj$jXYycPpMxJ;CDxwR9+?a?0pr^E)IeB3#^>;e{>rARhRomTfv~Xx2Ab9nv*X69! zs3dcrO75oRW6!M>aYMxNs)qAnW5-{WPu(A_S-Z6WA+j;6#75LTJ#mk2YAahdiU82U zsce!cco9{0s%LK>mp;E*w_yjF6M3*Z2@5hz((Pb*=bpTF9eDh9lT9LNC2`3mWyorHOzSvWobI9QFR$e&dxl~yU zFfKOC(iPm;=Xv8J+n#;uDJ~u>D{}_rbuvW^D#e*2R2iN~)j$40ImY$?AE|X+)P1$gWe&NWsfSfy9z?g~z6PpRcAXJ)voQxg(Qggg2PQ zvCV6}%gTfIk*I+{9!x<`%j=G$$TY(M5xrkjfkpu=d107CqdFKjyf!?Nhr-t0i<~o_v_u@Av0G^(_bH!VQ)>v8- z6i9|cwV6lEy@?%<(z2XU+e&IN8xCbbFxejHN6HkIX6gy)OeK&*JZ3q9w2imR+{ZmY zKAFb{ijaMo9%yZVGb*Wwl`;9Aqt_sM@lr(`O+1JeP~lErAG<5u4{_A`{uRwQE9hrd zT}k(G>C@M!@1-8$ z8luHxaSUOW2;MTManB`z$s?%u9Mu_aUgQ}W?OAQ^cB>>CfMwx<>9}+RRa2VL8S}QR zP7(>_k^tF=5UgVRx$D6nUcS^jM{1~{OI%NIzEd%5A`UPBz~?#1$^5AhDYe89EvDx! zsJ}!jw@)^5D9?p5CDQU2ajBgcjB{WoW`O#TkOHg?0CVDlb$&B$ph*1t9EHD zXZMfid8L#{-4{RodbK+jN+~@`t##&H<>L)AAHMvZ-lx~roY6xhfvt#X7F?3@Z5bU$ zrfHWlPX7S8h$8uJe|eCnYhWHg$si1Xd-`UhFh&a>FbJ*FINow4ciAS2>0#YtcJR1VrO>wPx``}TWH5#z>;x_X|@)63i3}YkvE#t&dgfj z!DcPgl6^__>t46v>pN()#NL-{I~8rvLAg~=QpY(_y8|G7Nb6pE1SvvSZ)a09AoYfFi+6+#yu-T>{iX>7{STI4cH0?0|SoLa^}|D z$Wm3w01`uFFFb#T<6TNhF*&5H&L`|ML2+#EViFl9{{W9{mSxExws-{e~b}vjVPGP^2%QHHC3)Z!9DwtIsl)*pYJ5G3W=mJXUvv zpO{19G7Y@UWu0Mj5Ko?PK2X`m^&NdhVq2-Ty%5~mPDIxWvPfavyLmZo;2&D(8Dh0I z*=UNiW8{xKzkK_ShqoV%X3lQ}#ziH8m@=~fzyaHi#N_kqSu~N_r38+qE1?g}h+~Oy z{)-ky;4^>$C#Oz*Xf^bLp*A%%IL#CUG zTN6hY+FU|pjqW!F4HRK^`fxet^{$N>;gwMmMnXU==y-1R%v%7mDmaif%ojP0iRYfj zpK9n#tgG_L{39WIcC4V<6-K#@rR039Lonw&(^!=t9lyLFbL&{qYARUa(bEIwEsvVC z%;nxSMO}>>Wr_Kfff(bbuYXTk>5Jw@HnE>DNaU5n1QD?F0RcbcJW zY-5Pdw<=0)9$%G!tgFXf-#1P<{VCGNEJ9XOv?a`q3hph1KE3b{YOw?hDx^`!1c|ic zx$EswUx^VHox}{18}9SZ*0O%_+3hY)mkk;QVpnio>yybnY8^sJKv`{oB)9{Eh65E; z$>zeT8yOZERzz7w*Acg`d>)`4Gxa8=JKot`1{>ns2qT3jraFVyuc)fCM?8~#47;nj zCCp}My!qwZA{HB$*OS2q*Xu@)ZY|M)l}Q&YFs=%)8T+TFUgD#>g$uNb$}tXP&KGbV z=YW0x0LHRmNejk}BgY&nHb(P#iyEFvsled2PfqmhbVn;Y=eCv91wzJ1&H}TXbDU>@G1s}RoSR2PZJ_pNV zpmUzX{{XK@k@-^dAbsF(8-8BB$G1w(NLkwBGe|eT?$MtrG0@{R(M1$;ByK_7x8~Z% zjE+a^-l03ls)L>^SeuZK~}+9H|M= z?dgg_Gafl(v#tedqaLR&rzs_j*g&#vV6CyFBq+!{kOFwlFRLnLVDF}xzI94(MV$QG2|25+e$z z%HE3<@Ia#4S24P0u8?nIzaC+x~ z$o^FlT}t7QvzA!47@8$j3OL9k+n>bJtg&)R=0tg+^cS6oRExw;ZIO7Gw*|47n~+gA_%I0?6-{q$hrH&cU)kM zeswLf`FU2wSH87aVItmnNNh^JYPRfhG1DCZ3^QsWg*GG_uPlmjE-%7zC^A>fJh=Wc%i~HEGHtrO0^1LQSzuidk1VRv73T zsKL$%&m@ZH#A>fJm=TtYF$83=Ju&?GtBTMe%_eEtOfMP+jol(=P&|@BW7LfL{{W43 zk?L}Y?)>7&nK6Zp3vJ!N#yP<5eKVh0;cN=PZRVOykx4I^6ed7fzVhXO`>nw^KF6W0 z_L5|A916s_T+C0(RE~d4{&khLI#RK^rV?^3#E?nyvN7kUU+d4cG$O>$!BugEeVa>1 zo-#XCJ9&~ej0BXt(K3W~%J6#iJog>X<6T0!J({vc858AWARC#u&u_=^reg1Nozx?S zCbrAR6iC4CbJU#vU279ih2WVaO@(%y@4|*X{dc^yOCV6Q^O6Q zU>>79jE?n6=_XlOB2|`2QJK8*O1Dh&&L|U)GBP49Z*jeq!Pr}9R#m~{t})*uKhuoK zjOT%KDu!lRAwv;Z zkN`{97k53(i0%_($uleMT$MTP>}qRi?k#0od5~Q+3WRpsIs@YmTVR=K_)Zvf_d%hT?EEU3wdppYln>hlVZ$OS(KcU*o+g$7BT}4 zKpgv5NvAAQ+QGf!LcyA7nE+&ywmKFA8P6R4bv9=_o!Kw;d`^~e`EFx3SiWCB=3sxi zaBy?Zd7|gS(%dwjTU*A350<62vB%c{=hMAfn^cC@CV(B$B$<1X6T$t#@y0Q&0=4-aXU zmlqMjhE!suE?X)}`fcob=DPOP<1laYB#u`AqDyR8GLU&}V`=*P)?Cn*K`<;7nI1V5 z5IoFajxnCO!Sx5;h04l;sF>(&tYBq_D2H=xQiQVu&H?BSdCxuSb#RDmjlsIPW7w8Z371P->!X9sxqXXnuZ-y9u6kw=JnA)A@nn#l1@jUou zc5+E4oS#!zms)zvB1rF=ONk_9IZ>7!iNFJ%Yc+MXXl_fGl*AXwiHjK;MkEjqJOR!Q zF@xOVszc(4Q6aV?4zcZ0NCb?Y-KzQGk=qE#q8YTg)SQ0u5bCX#8De{mzn^O6wM{Zv zQV5tbJWf}1g8`e{*NW}o)@@Oyl$kcf0>Sub930|Adb1N4_WZuscj;cw4N(_gl4sov$dDG z-Ru7V>#3ElTov~*8&i@*k~tpYE9fR%BU^%|Jn~7;8SFdc`c_V-X&w3z9o!Ez?I1AQ zsl;UT$T%c+>P>Ayr`-(s@W!b!<&3eA-kItTr&`I@6YUnaFvV{Bt&4o{F;&O+vz(57 zJw-INS{+b|a#lPy$6pKWd|hVo{hrV)YI8Y=Zq7URJ-GJw&3rBKXZC*8bUz~LH0zt2 zLlk05q$oOxXadvGU0U$FBq))zw~jTSwO{9z8-Aym`*& zj#x^@g!KOacw_ZG)zyWSC{$9MZjY$RIHwztR9wFFdmqhjjy@G$czSDlsH|nY`(*MF zaU{*U5OPmb$Q=TXIT##Qg=@B&mYZ;ZZWFv~*$i{Ks@UQ5L;@|Ao2BW8a zt4{Ln?p2SGZ)?*r5jI&{xZ&c8OkBmU2q9v!;7veYeQ^KX(hjysJxX7YltU_+Jp z4nQD|PdMP>m0TOePEw-1)PF(ncZpPZhO4J2Ds61FcRn4{wHLQ|pfSdE87+e}w=C@l zAoL2X27Y6oUOD2uOTpeOnI*EfZCXeLsbLaaAQtxM7`EUu(|0)MmNm@lehSrWuI88Q zxAR;>{A&(!r1d%eW7fDk*yMm*+rwofCrWhk4Orz!V2>_CD_eecG$KxKSZGEg}Ybaf;q*n9wA0U|G zV$0lg>N;Ta?_U+^`i8TkU0VyuAdcGN4d6V?va12X>9=VIu5-t|cX~I)3zU^~`0owH z)V^8^V0Wk|a0L_`_3zV;dRIjnyq4^KYnt#BYF<=Ns#8jqOX#Lpu47TcyS#S|)ME+ySH#zQME(iIeNK@2iU$RLakE9UJ7;xuzyNgk*-#NJXJLv&w|W& zBOOC{U*-N~nJ(;YUg0kG+_c($*j=3bqdegM01FO!cCL3)gH4uMeCt^C8+@#m_L6bA zuy(QMk~5K>v(QaZljNLL}DUE`Emy!0;~^jbLmxVJPjtOw^Le83=Q^x z%4B>9;~j}77(G4z0G~}d)aHD}ehLohr~Y|e`OB@c+u_bbWIkNb!&VDL|`gb8vTkO(`5e^W20j?3pJb1qSh0y1%`{el#BzTEAUOGR z)s6`C4u{cg;k>`M^Ac%b zwEg6aEnv?*I-K;!0M$#K3U-V|b$=-k0?OB6R!n^`2frS*pDKgc=!Qi(^=2)y*;&aQ zq@vzOwsQ+jXyM~rG5d_U1Owb2dW!BXWQGTAMkQhPvcGAZNJ}`$&r)ztIXKTe*EW{+ zwr?W5_Qn`sR)JV%GT7rIJb|8{uQg6T8|d~It7?|8qDC4r+te&-Mo0wz013e0XSdd~ za+IFOrH0_#O=)|ux!g~9_kpa04G=RVaCr=55_TMN3FjPku5wAOG}znDxQ!p@iV|CE zGV*Xe_|G1d%4+^Kw|$>txwnQkm*){&7;V-7Ks&YqaugGQGEdhv<=!Cpfn`0?jXrBx zZSF*iwmYFAlLs6F%8)@E^UpM*uh9D(tAW&{y`*$KI`_mDF4kb`R$6qh-ftJT5to87 z$Re0;0ng15Ll7P3+O8v(S`J}`o>ej zSR5P_ewsDwzynMvV_kjcg6oZ_Tk&IRen&oT+ESEFI zePFTN+!3&_T(0odhU_% z{{UJxw#FSMW*3abrZ63{NrA?3>4ELVOmQ-v;; zI_{kb+FgH}H%;*KlIa4t}ia-Wy^p9Ox-9|on;bl4#A2AUZpc5*@hLmZLopHIuz z75W8h66uz5*~GT1ED^Dc!(fo7Kr!-wTYxf8a%(OvF5kn_JQ2qp=s*_HqlHx&;Nu4) z860El#Y)$v;aWHH-*G=a-K?UqrG}%1i;CR*Yc$M%w5lo8y@oU)-a#a*9!6Z+sEn&^ zIN%U_VtIjV%YWO(jSPu(GmS=+RPv&!&5zH$+TQu^@NeLt6UNEiPla2!pq*pwF zrjyD^BaI`JtgPUjtUdY>^seggwe7@_+s|;KQdjM9l?{$b1RU@{Ami7sdf@e4_VUQ= zr^|+2lLaFTr$3%QE^D4{H!zf@nX71$3$mg_Y*{-At>8(a2&8b&ovKS<4(FU^u1DrF z`A)Xz!Y$FX8IN}a@))0(4mjZBfz5Gt(^)|?y|{m}MvAZ)9HPd3*Bu8>txtJ-I?Ay? zG93()Jb*A@Gl0Fr0s+sb9nEH&xaqgdSiPD{S<*D~nU+tRC*<4TIIeqCyP6BT*lQax1uZ9*QE$8Kml8q{$QObL1c2EGARk|P#J|?A;lzm=y{xhk zA(9|ibDxx)30@?YmV|%f@GEc zNF~WrBxkVckZ^wrw$B=)o1LyfG-FSmNg(s4iYc>fw@__q6cRxyaycJSR$Ig{$f;>E zZ%K0AU)jD>oB|k*dJc!*9{L)LmRCenwFX_-pN)c7UC__ zrL?|W(t9faa83^=r=@aLYnyYjjk#6#E$UW!UH!eyy{DIMJf{BuM7Efs#-v~>9PR)P z0nSGp*Eyp}9fY!OjLOhRB3S&*+q2O6o_qakoYZI3w0WhwkRL8myY?_eBDgRNe9WZd=3sht$4~Rprjm`#B~eB`N2^%dlW{6a64jtQ=^-sVrT-HpU0>K{2Sa?E2mI8u3Dae_N! zbTx@GJKjLRl1AQUP1mr>tAYvoGO$fb;#k%t-i zy$R$F!xX1fceb{Svn0`S@}UhJgFQI($3I&271Az(IZ3pu)Aorbv4{H=9%Q&=1NX(( z_lv**IZ=a-xjsLy=~}g|#7NP`lPM}574pO6?qa}j4^RN(f$LFH)*S|>$*t}#)s?%T89_91FoW#7n4X*ZZCrYHC*HB_^job$;r!+KP^zjU zurh7~l6W~7;0`$VuG8$+T3jop%+uYkl&clPy0b>v=tck_^V6K4<Eqr)o+zC?$>N zq_&ai`>th$TVyuM2zd`--#O!ozi)eSrVlD>Nr8$oqIk$C%=|FxoPq6*X&z`a*NrWR z@?8m@UNWMtH1^Wz;moTVTrciC#XS0S1l3DL?vW|4k+T)rF@PE4jUi#Ux&?Mo#yH@0 z$ZG%1qVqKZhrXyy8&Sx`yc>Xl|E$Ay|w$h9!C)8wa83&0}0^ z5$SrQ6T=0{$qlqAB3#ZSzymvgzyVv6jC3Fpde>fFTb7t)1QagK1T{Rm9WmIU?{_Xc2tb6_= z`hFFadvB<`60$@ixJ1IP&%K|=)BN_XBSg4uK6KNs519?5rHlmOV{XUv$oH>D(zSVI zy7KN`DPC(iJoLF)#@;nZ%0JoS`5;|G?2#`+^Z@n z0hiQ{NcvWHonr9Y#v!?mD}-p~TRXocq)ZhmI6FxMu6u$j&2J{Wn%(XtmU4W-A|j^c zW$rWEoF08ou&$Fq)cnh+u*z8=aNCptQGvZDn+2 zoT!Opb0jh6kD0T<$sKdS>Bf4?)ttia3r{i-&mrS>27CMQS{@tHqqu_b-MlBum3Dcq zGDoOBo%pVatZZUmDkk2}-B|7_bDRVIN8wFfnaXXRC#l&kr}lR-I!x>4OwzvXug>qA zsTt}1O?ck1;gpVBi^#0v6A7E`a)}6$Wc#a+?|i-cU{}?;wviXuuk7Hvip{QWA@gsV zFwGi+oB#nhKg2*Mo;vg3{wua?QZsa861GjNlf8)JJPdQ!*RQ>E*Hh4{ZOQ1)e?+ml z1y~RwLP&79B!T^F+dMiguWVe-Od>T=J(+M-qyT{?JqZ~efZ&{p^1UBYnn>cyZ7gJs zBgYD%dgrE1Y}nt+3{YB2Di;bcRE2ATGD-gccmdFH$E{~Yx^Gly;^M5MIU9}u zJunaStFPhz0JdLS8>pS)Spz6+k&J)!{{UL*_K|4DNlM;FoL*f^3T=uxETg$q#ApuE zy|MZAu3|@q*!{8GN#>s~V=*C}N&GSo^7gN$wZ9Aadg3_uT)>4wszVl4)UT%)>Dc}? z<(?z3w9^r!mKd(1`#UUVNWj9L7FOH$SP%|JuQ{wegIICJq9YKD=|mJbgVeTT`dYXqiHrwa<#Rn+y9} z>x*!{e$l!~l$C6`VU7-X^{mT-bEaDxox|r0E)-=}HqXkdl1mM^`La3B74&Ya;drLM zmeT4Qk$-a{va(#5%W`ScHSRu~g*Et@(zLoVA%bP28XO>4v!myHL0b$2H zfz*9DuaG=571oEZ{iE!V$t-fS7@9_nc9M4V=hvrS(!Pkh)Y|Jzn(>5jyW5r)&=SB7 zxEUw)^sbCN?72={U8+`6j>9fBk>VTck#P*I9B}Tkc&*M+xH1X0&ITB>@(xJA&j57(RZeY@1ok$(87f}=uI5(+0y6Rt z#~|~`_x}Jq*U%aj#kIr`+X=2Djupg_&j^k<*tT}3UCWFd`jRold~M;~S*`35ZQyXJ zAX%kx+#GxI2>xD`>H1fXH3;KTWESYe%N@y)M1ePCsoR|6BLt6cTIYr%mQS(0N-vXR z-*2a1ChB!)q=MXqwn&f|%8)@Mj1WP<$364XxGUSMtC_s$3I|B>BCpKL8RI|hlUUZ? zB$DCo?eFc_=|$acqOrO#v~iP`SlEJBjQre@*P5F|w-MbdU3}1OW=S@dkykkj-yn<< zeT8c4UEU^8y(@P*JugkvA-IWEUFDv2TVWdRE#Cva?wk)=_ANf(N&=8%nrC0MTo&d+ zdYtvh{(`)|E6aJMFvB5fVZ%NTAx{I2qo;rAT~3`n)vOubWigW2R5?&{-`k4Pl;q?o zH&v^in{L*zZ&jIPd3P*V4unh&uM*T#K(WZ|`(lhMO2vR8Jp1$q z9cp#86AjQhd9M5va8;K$I3SRC{6C#Vc?y_Nh4SE(Flc7MWeTG>AOHb8f!CaNrLt|P zjSEN;6$(_u6b9?T^u{?I`0Z5Yu4O7swohbawezCWr+Y~EEOW&gjj|{?DszxjgM(bB4aJWZq6`~<(OyI zznwfp;uzyGe^<7VKASJ1@b33IyGuouLLv_u++~tEn~*==2OQ^$y&s1+T(qfdk9eWB z$W$6}+_;caeXaMt>(NR!+U zu(49boSt%h&3=8APcOydlxDQ=(Do`(n};-B$5Cye-P;M=+n=;7qt9=YGcg!qF~J!0 z`d3|}U0d7AZP3YZV3~HC$QBk-f8EY~z5f6@+S9LLl*G;CG?{4He0;-$$L0L1VjT|N zFSAV`^FC$R$%R%Uo-^sie$kR-cuF&j>9up`s@98dnH^n`ntNFwZSu$we5rObENz|+ z22MS3OtuOnk>x6^0SYp5t?fyr%J2!Ioh4U}Wm3*UmK>0H>JJ?$?Gnp1+esA1%un=U zr)kb}lfmGQ!yj7xqX8(&lJ0mlIh9uJp?@&W8K!|{c0n4sErIAx2pP>Ktf5ShZ4((z z&mtrY%%iX;p(pzK)?O~ds}@y@jKWlwz{$_0TC%$;3ocOym{87}S(hgqbp(^1Yqn8M zqLh<*lEm;^53~tnNiFUjPX}wTTt?pw`k1B z9nn}7865|I&)SyS)uo%ww~b?hJ-J!rGBWee=6VXxlErexqHAfP^2B#?!n%gmHquN< zm1F)SPQh5M|RJNj5CZuuCEz zGt16>@EG%fn&_8CwRof4jT8Co*f}{E;A6KrB$M2Fa~7Mio8^VhE@1aJIc0FG&QZ8# z=y~Jyt5Dg=8pgY=R%>|)2|ciz%wg|>tUZoLTI*9o^Q0|2+hQMjHalZqfBw1kuA1)=dZ6y>Q=|go+uFp6`SN_1eecWUfc?^b24u*Czl-j>7QDe zyvWQTr}`vHS=oqUSoP%d$GuovWmgiQJ2!^%pE=#!(3(iaCl)|fWe{;9e)Wr^e8<@L z;O@xwBD8?>B#J3umEX&dfCkWHnF&Jw0C}(uIu4Z$%11PrJX{A{WbnZC&r^^GPWi0)o$PBJwb;+M zk`XI97|gb?vi+bb&Knz)9zC)L2Lr8MQcs&Fl)#vmZ&K-^QC?|V&5W*d4ABCrN$fl1cPHN!WajL+2*{Br`L^e2$5KbH zK~$|{npGP!Ws*4Ugqeh6q>=y?PJL>f+s!khFcCzXmT1+=hEGw95stO444=D}HYqpR z^61cQ!tyy*9mibyn#~BWak1pY(II7595M7C&Z6m#l%Fx90;@v#yMwf` z0m7CZ{MCC~sN|7ji>l)*FU|PpnWVb`B(BzSJhsWf{*`J%6cMnw9aGo* zY9u(?>{XIcwRYz#{vXbs?iU+LVgno;WMF@vezi&|6}uU{Z&>y&$5JF*bow9g^rS2b zN>^c2U^h2hgVXEYspdx^!NDj?M!bxl@aCgyk0RjPfitX#Sbw9PqaAlQKzecYtz&f% zaV)B`@0Hx_W*;+wv=2{TbM>b);47~PADHo--0**|(wMBuiyMrGelVE;(^@YkCkV(e z%oH~{KHk+1S4I-LU>SdV6i6c>n=A&^X7>Cs&#xV-C?b|rbdn=)wa=EB?70B&anm>k zoo{U;6l;gvv1Ecc9>3&Oy@pv_za+sEE+N12Htyl}x0Ie~bYiCi z01wkXg0n;t1Wzt!okEs*q)@EP1_KZ<0s3^J?J};;h&!qQBV&0VyI^upy-AYttXRPS zlHJPIMVW@y7~@GLca?WYE~ja*#PfpOft=ue6>42j47%(-Q5%u7lg>ED=acD9=*7FU zNbC_{g57qh1E8iP&6Q?o%I;yc7;Rk@psosP|;?*q^Q>rN679Tqad z5FNpTVY$c$f%wx*LvL@PK<$t`q05%a$Ai^}OasT(u$E`GSeIe*rD+=DbjC#tNhAV) zhn_oPugx3D`@xiE>BG2;g9zKl=XwTB^^T#Z*Lqe(#U`bbUSQ2D(+4O3thwAR?(4 z9=$3kq=U_p*yKi3U}Ggg?ZXJk_^Gj03QvDGC(50x5?c104lEKJzSnW20HuH4K2JD{)8IECO0w2C-TX;+@X%*eSof&E$!xy%8Dd` zR$b8~A1du5>&`v%>r4HUXAvc=;+Vp_qPu0wBXf|v@$a9*p`zDAaY-2~Dqh<@=8|W( za~Vk^Wdpw)V2)2udd$>s77KVFjgm_^PF4tG0n}$DRfr^g2OW5=K`PnD7>vJ|;IxY? z24+!_fsTxMJpNqQEhN#8K5-b^3l|RLjmikZh2&?cB%E~j&Q3a<^Odf1S9*-r(8Y4m z$sBhZjl8=E$@Dqzf-(=SA=R#<5xlCiM8g*E96>`j1dR71AbkbpcX90{QjQxnJ%JY znYKt#+OIn-X!OoFGW55&2DK^$K}YZFh|TwJ~t2X{{R}% zE0-suHIhk8K#h{SZd-U@`I(y>dJaz?om6c_qjyyE<-|&7M#BY@o}Qx}{r>+4hBm6JfFvb)9Y5-ThEq}+QmHNHW}pFs<`&=-r7lp|oN#HjeegmA< zb8{WUNJNtxi5Qt=cgbezdi6DpbEw4%r_N}EXPgj?uzsI$0lI!Avoa8KQ0IuA;Yd67YeRd{2Gw=%!p7#^9%4txIqO3qvN zk~v^WQb_}|5Z^D#Jpl1Q4!`|spfjI7XNf{ejplD~zf5}lYYtmI$0)5#Tg#x=6PWiP zBy5OhmE)i5k9vY@^DoXAv%@1U^>ElA`s9wZlCP3pV#*98vN2q!Kka9z_B>V{tzTdZ%c(YPjJObt~dw>T<0YA&MMqj(ajQ{ zvrTSP92sU-5-|SmIRN?^T(W{UQjL+)myS7B2(uC}+{IV#E-NoRStRc-M0?9)J&0dQ+zT z<2sgR%rfn`+QDAgqydnSaHqXpi%#DeiRF0WoTo^1YYH`KCJ7KSzRjj3 zQ<8DUG2gvz+sQm}t6e+Cz7rTgf-xxX{C?t{4bIt(gu%x@u^{0_;BZ5~`5oL|gh78>>cq9+=*1TWh zPLbl7tZf8VlJ8sb=Ag>4Ry%Qxr*P+?;=H_TlrYkKuID@#zoNT7X87ZCqU*jEy0(Jk ziDi;S+^z#Mupo?MoQ=ciYw^$H$AE0*@YvLr*?!S$9IbCTUz=*=jlI#MZ?rN}h-2Z@~Wmi54ClORo>#%$D(7B5jm83%k?~xyJ;7 z&{y3)7SZ%C6KT+0#B7x&o6H_v^2o#ihh{6(AG{U1eR;3TxO^9T9n4ys)>ls^mlTbs zUfN!HakOWTEW!p)0I}R~ayZUScfJhxi>zo6-dNk}Qp0v_$CS_z6(f8po0bX3kq~2G9mMInP?Vs_XH18WqwW`)$RFwlul# zmQ_1JJNM@ue&__`9CLwPHiNFor>k7wD?xR0y{*7hP|_TI{H|O8IuqPim};L7^j{wM zfa(%K1nniqH~ceikC#yABOL}hjw^vjneUN!R5Bnybv%jLCMc^$<9r9B)=GS-3wA(R>DhZE=K&N(}@lgjOPOfoSml~fv=!^ zec??9!=4bc!?T|+`cagN-M zr`oahe6?1m(bB|WDZ<;QhxH{{E)svXNX)vuf-;hL9$wOS3=P1x4_wwC#7_|DmlihmQC(kHJ4UN_e*_z( zX)%QxIL2E5p1_li1$#IO-1f27t4?!N?8?6tyisxD>twdKf+-d`h9lvL{0|4|UPB*) z^(E7+t)fV$w~gab8%!fHu{?mdJHAkO;|Cu@(&@TI{{Z&Aq)^&wT9x$d+hC77vU(B; z83bqX`d6=bi%HY;PYcbcof}YxF3o*x*UGX&z+-tJU@mzI2_qm^wG2nGMdGMM#VD;$ zBlxZ0*bj#EtwT@Mt*zy>hBlwfw0R+51~&cC^C|7quUhi`7HwipBTh!W)gWX>Xe6|^ z1!rNLrU?LZj-4}IPm2C7U3iy6vhb#pV0NZ^DAL#Dc$jC4!`?I0;conI;vWwk*IISm zwU3rrwFHX>Nr&CYJ$N|C=qqCT;_c2uXwM(R(gh& zK-ZaWKHKuY-YQS;zm*CG;h!mjDSvfIri&cXzM-~@XdsJe1B`PSnYQGk|>##V`UuV zvH5`nfIV^TUl{yU)Za+)B=BjIeXbV6Sx-H>E0U-20D*&maa~uVUh<4l=hacf$?~fs zcf_6+O*=!0e7Co~*sTFY3?z&Xn0|G$;NJ<|>Nf4FI;ETwTLo)a)SZOj;ddO5OrCLE ze}p_&tN5Po!F4Oki^#0eqmJ%kU9+E?8%JZFg1(;c{=1}UdL&WYM{jdFk@nZQV$URw zSSx@zIP0E+9QCZ{2TqpSv0<>dx^{`ec(34_Uuib?ma<)1YEVSb$2OaGW8V%5V0pki zk%8;hy>mzK#)sjb27hJhdWEl?EaUq$7a{!HiI@zi!k?IR!(egOtvgupED-p5IZ-7t z+fLqbG65Wswl?kHoQxBm`2&jQ{5RqaLjLw!onp=_yLn-W?R=&UBB?umb?T&$cy36+ z?kmQvTNbFw^U(Sld3HAuN8Z_b9xJZjTz#`o(^Fczw$p|5k9h{e_H%2|ae@l4C+~Bd zoB^EIqj;}O)4WNbM;C;Ryt;zN^WXVK{@U>$!`ZHGEn00p!e9Wku)bzhh@GJdWSyjBbJ+eh;Mc_` z3!bJED0QtU=_vPK@D9gD@MJy-hU@!!?i;J!LO(Lz3tN!4F`*+NNF|dv$SvuS#day6 zYC7JOx{O+;tEbz!D+Z61aa^9*U!Es_|xI5B@o`iR_{`DVRosyW^QtW zBxfTB2h)rU*Pht?P_nqzA!sjkIP}Zacu_^%ke@Jy8;DjQ5!eCNyjf$S-ujd^6 z!q)bEI^|^DcC8pxOO$QE?kwtZFh&A~;2&!1Sj6pl*__#@{)dR`{4foT3-*ZbvW!`iIURl z8@t7fE6mH}#)CP);AEeEmF)Vajp2V4Y4_S^h%Ahcc>+UiaboESQZdf(yMuAmVDr|! zT6Lz9<&WNZxrGWje4KY*dFC1i?GvXp{k@}E+#8L{9Nu}_j@aW0amXjA|eFi=JTf@4q zg{|b%EiP@OlEO=slF`y^Y$(~`+b1B7I-Z8T)ipl|T*n-e4L<(mAR8{^D$+xS2jo4E z9cpV%aEek#!{-^K==-v}Ux^OC;m;0uqS@w8vzav~aU`}D!DCaL6(^`*c;}uETvyM& zF8Db%iW=V1*3{a-?6zzzfMTbqXB?5x05j{}y=PeXm81*j()48WgJ;c!A`G)kqyda^ zxE`PVdgSi@E7{#gG*ch9Nn*>Gz|Phj;2wwn0Igc!sVl1^=VP7bRGRj8vFCmq(zPoo z5^Ybz$dg;ImnYd_FNNqf?E^W$JvsXI`WM62w~{rxCZ8p&g4t$;#0|Dd18`*x)qU1{>lHu;UPI*4St3x7O_jMnin5yq1O1`dAm z?d)-aM`6!rtXw9Mr7ra*W)0>`B&0@oEZAn?^}q}41$oV;t*c$zs@%ooMHI~F_W8>K zJ$*6jpVZek!kxoWRWDii)4O;4sqg{A7Y?{THe8buw`w2;F&kSc~h zD9Jo$pzT|ib{6(fMQ;p{K_f{UMKVmRUNT58CJEa6xY|b`gT_XDPrNOEYbtRi4){tdlllnzeB&h zHo!jnjgcngY-1S&9CjmvN)V?~7v?=rt*Z22EnB92(cw=K+D~r`F--%>ZwT`vF)1s! zw*YtTl6(Gj-@_`raX-r(D!UaG1~%mX0559zqrm!~*>yD+(cHvO{Iq!jf;q?5zRc3* zx1UUoPqalN>;)l+v18iPD^EEX>l)G|?@% zWI(=SM%myF;BLn~swo@H24NAmQwTE#!w`BC#~k$^QC5;foWI#EC26BoLvpZ{XjC3f zPX$RJWOv6r8nEkgF$}^th&Jg2Wp^_Ga$DD?G4!t`$s^|Eq}wt}+ggt-#sn!0Z9B0z z80R_cJJsz;?Q<2(Y&@{bB&hB4FyQArU=j%x5^i^zI94$U8DStD2<`MZ=}^MV$iP9q z3vhhGsu_klg^Wi3{EqFf$M^K=N!@rmefimU8PhklQ{uZc_o`X-~o<3eW^9fV*Tb>8=l=G zF9|6kw%2e=WF9g8dscPBM(tw^QE!n^qfm3@ta&F9yum4ib$9yn;=N#ed}_O zv`|R05}5&pdVNP3HFnm{?G>)p37*;~Wu4%SnlN+5Pa}Xw>FZYDi9TrrpS(!bg9w$C zSGH8~f^nSs)MCSxklYC}$8tu;gZ#Pvl%*!V6RI=cQlYht5ZsiKUB5Syk^v(Ca7R4} zBfU{@KGSTMa7xzGF=?#nadBjK+i0>$UdW< zxTJ`}?h8ux(Rqrd>PYtPP%O&D8$_sg3O9cdj$2d9T6(kLB zaX;_v_W81Y<8b*wAN_ic#?~vSV@W5tjpBT+z^l1NN%@X`ZaCw=tv>LwcraBWGQ)KwUTQ}3k{Mn_ z0}-G&$@Iy<{A$#<0Zc7&@BteynC&=t)C0?sxyK%y)v+S^V&P+o3sz<#+Au&>IpdN} zIq&%Qu11rQxt`EmMpi49vzWcF5!o-6s|fj5AxXnva!(}W^)*&hor=aTVYhs4^RCgE zSDpql&m82|h0L*lsT?VATrr8BHe~=~sTlR?oSuCRRW?y0$t%NZM33f46ae8^3oR@o6N9Bu#Kj##e)%lzV$0^WLJ4*+vJJxGd3;%Wmg`{{ZUrtCDXK z!Y7tU#0X653}Ri(Ps^O+Aau_kr8#7V?8kvDV7b`i3;ur!Zt{DXayt>Eu|kr{k-Iz$ zss`Lf6x%!&yMENo9trgPWR+O9BnI-;VwfJBl=C5~l|D5MHz zo!b~aPXL?@9t9@o;b`SW{qUKYNjrB(&-1C_u$m|tW!oYws;(AQ^A)g2AP%FBqubO~ zor=&~##9-aH3Y~2Wm0YH~m`g@KIS4pLqN#@Mql0DJ_OA>kgNj-nS zRuyE?&f)J18o!#dO*w`aWme0xD=8ea73EkS!?C73N^!C>$s@1MvIb>b9#5wuABgQz zK(I?~d1)ifwotCi6A;V68T#Xl^`}`{N#v<-G6a_0O0B{$ZKsta91)R&&#hyu*>Q|e z*SQw9(iyJ2wKF#O_4ln5B8M5uC~WO@XA;3Iak9oF`H_T+xMu(! zgcIM;)E1k?ywV1Z72$6-264NeuW{4=0M|{P2F!>{GQ%pYX)jVq;{%^#PnS+x$Su}g zqEjyI!~wN`$gJu(qLX%IhPgLUtaCxKCc_yRj1oBcew-i1sI}(VB2w_cSZywFrMST3 z*B{r^)vKiPtyVKK{^B-bxC^yMQ=jwFv!&Y7MHb0T^D-=-Qs}gr zOJ=x0NQ{8W2*VD?)Z-ZA)~s8B84EZu10K@uNEqb*09tZen9glvMuz}~% z6x81D_F1GLw0>m7<(QMuocf#!-K9=Df{n_?@6Lfz2qwXHLu{7J&h8j(3KSjLQX3~7 z^Ht)5Bh1Lep^uoehB2^g090~2^&s@)oYtCL8x}1Vp>b}K#KM2F<8VHi;NbKop_Ww^ z@=YqDK!bdj0##5K)rTZ^=A+uS_XTFinap=GN#sN1FpZTTD$2vS=L8&s&!=8!TNpwa z(Vk=xGa00iw%HH1c;x*lCSN*92)IzY6_BwD^7>$R#Z2*Kk_LHXiQRm!va)~|1ZF{y zSCNc!)EIOKe=ZPXE5c!@}up(HLoxOPW=dDpyXNia-&I_54xMAFrpK7^Y!c?1M zm+cY;xrzO=G7xu z#UmvQK!F)#VT^;4#dH1@uMMP)JuwmIkDu&jAxx*Y1{a9b~* zJ;4Yakyx0{&|4hm-xw7Z%Y}0`?5)BW!-OnXC)2lV{xvji@I&`Rfn!BjRZjz)#(~!FbXC0C;kw zh6I8L$j2Gyw>6`_ z#ROh-X(FBp<$90DHE-=JJg>P}8)juv6yq4GHj}Ex&c<=&ow9C>fTuhG>&JT6g4!A2 zmhw501LrAQNwQi_#j*ha_W+;9x4h!EB`L0jdnZ=&rU~V!-5Rql2Lm}h{{Skm(Mr** zu-q&dE0K_LeaBpN86LF;P~16uq00jp00KY5im@`sZE&cT;^C*Z$Y(4R1|v8lxa*Fb z4@!R0E8;b$p$w`*Tm_N5$7Li8vlTu4xzFY8RkO0?$%z9KXnbzGg z32AN#^Isz>Jx@9IIXIV3UXu)yQ66`itq0^2U&j=`as4)2#Z z{`P9NMLo?T^2<7)EU`kvVdM?o{PI7oO4kmt%N@iv?*QAfeTAf6=i49Q_)#1(C~-BV zxse!{n&2|Bk}>8IxFmt|0C>pvro`qP7jr8aOYfiN+({(oImq@kguUYzPAouUxLJg1 z&k}>3po~)OK2ysPWy)Y%pp2zWM2T&sw}e`WC4r({t@d{3Zh0B!f;i)~SeQN63I)4>xgl`ddINz> zWocs#2rnFMwr1Q!o6pmnb>wuYWR7K>rFFQHXD4iE+&4@NanD}9)w_U4^(tC;SWeWwI z5pR}BPu*2s>`xdKH`&f+g6(eXZ<<}F&Lv||G6v{?&gJCs&p(_Gn?9giwHl z4BMMH`E#AQ>Us|KjaW)gLtkliu}X0?4-B@krb}jJbWp?-*z$UI>HO;T)SD3_k)ve7 zwsr*|o^hTksbAm5eE6Q;Ib>NvxNXhpo_ZY9S!I$r9x0(bHxfo$o`azrW}IN}s?h3l zyiqgFZiP?UA(QQBKIVM5+Zieg0C?$|f0@1?yi9=Y#yRVe%~6s#TLOHu?nwfb1gj3X z%3=#4QafPa@;!}4 zkjoohJ<7egA3yJxZqz*w(1H$q{ptxrL{{a(L?vbszTus@{Kj!!cII+}fw3I6ve`M9 zpqb>6cI5C!y<$w^%Lm&L1#z*yQ&ppR3$c~4zES0(_G}#U+!5Z26vw!>h=pZENdduS;Yj}g3hjp_jbpMO zbrLjVe1UfZh2)hzkELhLBY8^7rsrW*WFQuAanlDPt%ZT6GetL<45KP{Zc=;WzXyt` zsD?X!&d$nQ@3)Kr%%Tma*IbSTX(P$yabu#!sQox1~BKXx8BtVq=s9lXf!4oa6rhty3;jDN0Ee z;8~tf_T)1nw%2}Fj)eaJg+mS8kTv1Ij@NUeN2iuSDywznSYxhu9N_im6uNx7A(lmy zD;`3;ZIjM1(~i04`SoncwnmwxiXE=azmFGTcOn z@+y&#to42;hUs{{Z#TZy%X7Z9U9zMRd)!Y2!Fm zJxkyg#sJ^~df;BQ!G+8e2C^4ZKt6g#B=!5PEut#MOw^;c}&P;41k$R{E>w$ zG1Gz1eow7fHsRq}Tg$VOC>Ly38-$XNRmMgegOiR2uN9R9Pa`@ZD>Oj-&ZH{0Uu^N| zLT-1FVp$$Y%r|!D_=l$Biyv9Bm~PWQ^H-hLu)icYN`9XdzB-QPp_p- z6tbz3-DlWj+QB$D4e!^}^{Ua6y>1*CVhTjDaJgfgW4?Xp4{>U<;?X2Rif5MTu&TM| z1bPmADK?uhsGE-D@(EB(P0q<0(V|(1-LxF>)N!7;_o&Qjk;4>zY(=8|^pZq;kVjy8 zAED>krIhWqXLKs%!mA&Ydj9~Qty;I<=*c@7qPJg}3miEaAdjc5XYaN|Amb~tu!*E- zOd{Ovbx~;26C*ZHAa_&P4wyOWDQ@osgtTe94F3RWWqxEFjAyfU$*3kV+)R^27w_X; zuyAs#oRANpJmRe(^MdV&t6-ON_dv~PqS@CNMG`D_vfBRfjF%s0D$f>Ia*XkufEySU zVQf+szqF$Ebmu<|#Fa|oVNXrhOcR2N^F0G=B7I#^rGvX#G^Aa)62SeYC(>gw}$gN?Q zOL8zJkyTzz+sO>f-H+Cc!)}pA@WVJ|W@zLknON`%0D>?^MthEitxat*2xGesYTaTt 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�aByu?OzR5e=$f|uENFzR? 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ʫQM<^sJgp!P9Mx8!l~p$h^3iF${nb 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∨0v@uOJsfvGj_NfRlJaPnpJS`%IJOV=Vj&q+( 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 z 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
    lHOKTmOwxNcgJu=D}fT{GRY403le?er1OGv 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%0DfqG}8{*gcD70hElGt4jFvR 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%0A-N3VMpodA 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ÐBR|9kLTeuS^4C&= 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ɥ>co^_9G)4cC1+=nMvU@Hr>Z@3_XYW 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 z�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

internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,41 +35,40 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } - /// - internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -83,12 +81,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -98,10 +96,10 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); } } - /// - internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -114,12 +112,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -129,11 +127,11 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -147,11 +145,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -165,11 +163,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -183,11 +181,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -201,11 +199,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -219,11 +217,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -237,7 +235,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromArgb32(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt index 8c4c6b58af..0a58504e15 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Argb32"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Argb32"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 9232cf4549..711a9d1c16 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,42 +35,41 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } - - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } - - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } - - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } - - - /// + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -85,11 +83,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -103,11 +101,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -121,11 +119,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -139,11 +137,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -157,11 +155,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -175,11 +173,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -193,11 +191,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -211,7 +209,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgr24(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt index 56e3bf9ba4..84b89aa32c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Bgr24"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Bgr24"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 4f56b75c5a..b669dd5348 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,41 +35,40 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } - /// - internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -83,12 +81,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -98,10 +96,10 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); } } - /// - internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -114,12 +112,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -129,11 +127,11 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -147,11 +145,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -165,11 +163,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -183,11 +181,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -201,11 +199,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -219,11 +217,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -237,7 +235,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromBgra32(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt index 6563ff9072..004ceff51e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Bgra32"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Bgra32"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs index 81882185d1..288c5d92e4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,17 +35,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,11 +59,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -78,11 +77,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -96,11 +95,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -114,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -132,11 +131,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -150,11 +149,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -168,11 +167,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -186,7 +185,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray16(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt index 3db96d70a9..3cbc01e88c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Gray16"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Gray16"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs index f6678a4f87..f7e94788e3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,17 +35,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,11 +59,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -78,11 +77,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -96,11 +95,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -114,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -132,11 +131,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -150,11 +149,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -168,11 +167,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -186,7 +185,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromGray8(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt index a65d8f2634..d35843ccda 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Gray8"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Gray8"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index aae8b2f637..dbf3102c4a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,42 +35,41 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } - - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } - - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } - - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } - - - /// + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -85,11 +83,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -103,11 +101,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -121,11 +119,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -139,11 +137,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -157,11 +155,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -175,11 +173,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -193,11 +191,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -211,7 +209,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb24(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt index 796cdeb662..d96c3684b5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Rgb24"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Rgb24"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index c828053a4c..30c9972bbf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,17 +35,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,11 +59,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -78,11 +77,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -96,11 +95,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -114,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -132,11 +131,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -150,11 +149,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -168,11 +167,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -186,7 +185,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgb48(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt index b8ee99fce1..7bff336386 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Rgb48"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Rgb48"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index 9c29bd0445..da2ce3770b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal partial class PixelOperations : PixelOperations { - - /// + /// internal override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,16 +35,16 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - /// - internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -58,12 +57,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -73,10 +72,10 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); } } - /// - internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); @@ -89,12 +88,12 @@ namespace SixLabors.ImageSharp.PixelFormats } } - /// + /// internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); @@ -104,11 +103,11 @@ namespace SixLabors.ImageSharp.PixelFormats Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -122,11 +121,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -140,11 +139,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -158,11 +157,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -176,11 +175,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -194,11 +193,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - /// + + /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -212,7 +211,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba32(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt index 0c4a4c0c0a..6b9e2d1248 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal partial class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Rgba32"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Rgba32"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index db9cb84bec..42c40ad5d7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -23,11 +23,10 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - - /// + /// internal override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -36,17 +35,17 @@ namespace SixLabors.ImageSharp.PixelFormats /// internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - - /// + + /// internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -60,11 +59,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -78,11 +77,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -96,11 +95,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -114,11 +113,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -132,11 +131,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -150,11 +149,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -168,11 +167,11 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - /// + + /// internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -186,7 +185,6 @@ namespace SixLabors.ImageSharp.PixelFormats dp.FromRgba64(sp); } } - - } - } + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt index 9409e1573e..d15945f947 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt @@ -13,10 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats ///
internal class PixelOperations : PixelOperations { - <# - GenerateAllDefaultConversionMethods("Rgba64"); - #> - - } - } + <# GenerateAllDefaultConversionMethods("Rgba64"); #> + } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index cc8cb0e2fc..f0675cb5b3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -15,21 +15,20 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; <#+ - static readonly string[] CommonPixelTypes = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + static readonly string[] CommonPixelTypes = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; - static readonly string[] Optimized32BitTypes = { "Rgba32", "Argb32", "Bgra32" }; - - // Types with Rgba32-combatible to/from Vector4 conversion - static readonly string[] Rgba32CompatibleTypes = { "Argb32", "Bgra32", "Rgb24", "Bgr24" }; + static readonly string[] Optimized32BitTypes = { "Rgba32", "Argb32", "Bgra32" }; - void GenerateDefaultSelfConversionMethods(string pixelType) - { - #> + // Types with Rgba32-combatible to/from Vector4 conversion + static readonly string[] Rgba32CompatibleTypes = { "Argb32", "Bgra32", "Rgb24", "Bgr24" }; - /// + void GenerateDefaultSelfConversionMethods(string pixelType) + { +#> +/// internal override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); source.CopyTo(destPixels); @@ -38,23 +37,23 @@ using System.Runtime.InteropServices; /// internal override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); sourcePixels.CopyTo(destPixels); } - <#+ +<#+ } - void GenerateDefaultConvertToMethod(string fromPixelType, string toPixelType) + void GenerateDefaultConvertToMethod(string fromPixelType, string toPixelType) { - #> +#> - /// + /// internal override void To<#=toPixelType#>(Configuration configuration, ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); @@ -68,16 +67,16 @@ using System.Runtime.InteropServices; dp.From<#=fromPixelType#>(sp); } } - <#+ +<#+ } - void GenerateOptimized32BitConversionMethods(string thisPixelType, string otherPixelType) - { - #> - /// - internal override void To<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=thisPixelType#>> sourcePixels, Span<<#=otherPixelType#>> destPixels) + void GenerateOptimized32BitConversionMethods(string thisPixelType, string otherPixelType) + { +#> + /// + internal override void To<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=thisPixelType#>> sourcePixels, Span<<#=otherPixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); ref uint sourceRef = ref Unsafe.As<<#=thisPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); @@ -90,12 +89,12 @@ using System.Runtime.InteropServices; } } - /// + /// internal override void From<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=otherPixelType#>> sourcePixels, Span<<#=thisPixelType#>> destPixels) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); - + ref uint sourceRef = ref Unsafe.As<<#=otherPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); ref uint destRef = ref Unsafe.As<<#=thisPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); @@ -105,65 +104,64 @@ using System.Runtime.InteropServices; Unsafe.Add(ref destRef, i) = PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(sp); } } - <#+ +<#+ } - void GenerateRgba32CompatibleVector4ConversionMethods(string pixelType) - { - #> - - /// - internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); - } - - /// - internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); - } - - /// - internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) - { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); - } - - /// - internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) - { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); - } - - <#+ + void GenerateRgba32CompatibleVector4ConversionMethods(string pixelType) + { +#> + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + +<#+ } - void GenerateAllDefaultConversionMethods(string pixelType) - { - GenerateDefaultSelfConversionMethods(pixelType); + void GenerateAllDefaultConversionMethods(string pixelType) + { + GenerateDefaultSelfConversionMethods(pixelType); - if (Rgba32CompatibleTypes.Contains(pixelType)) - { - GenerateRgba32CompatibleVector4ConversionMethods(pixelType); + if (Rgba32CompatibleTypes.Contains(pixelType)) + { + GenerateRgba32CompatibleVector4ConversionMethods(pixelType); } - var matching32BitTypes = Optimized32BitTypes.Contains(pixelType) ? - Optimized32BitTypes.Where(p => p != pixelType) : - Enumerable.Empty(); + var matching32BitTypes = Optimized32BitTypes.Contains(pixelType) ? + Optimized32BitTypes.Where(p => p != pixelType) : + Enumerable.Empty(); - foreach (string destPixelType in matching32BitTypes) - { - GenerateOptimized32BitConversionMethods(pixelType, destPixelType); + foreach (string destPixelType in matching32BitTypes) + { + GenerateOptimized32BitConversionMethods(pixelType, destPixelType); } - var otherCommonNon32Types = CommonPixelTypes - .Where(p => p != pixelType) - .Except(matching32BitTypes); + var otherCommonNon32Types = CommonPixelTypes + .Where(p => p != pixelType) + .Except(matching32BitTypes); - foreach (string destPixelType in otherCommonNon32Types) - { - GenerateDefaultConvertToMethod(pixelType, destPixelType); + foreach (string destPixelType in otherCommonNon32Types) + { + GenerateDefaultConvertToMethod(pixelType, destPixelType); } } #> \ No newline at end of file From 4610324f22e3c6db4c1d9cb77b382915d8e17f01 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Mon, 29 Oct 2018 21:26:39 +0100 Subject: [PATCH 114/238] Upgraded Magick.NET to the latest release. --- tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj | 2 +- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 0ca3cffa18..bb559b70dd 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -19,7 +19,7 @@ - + diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 04a6802005..86c1a7a259 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -27,7 +27,7 @@ - + From 82646c11b728d2b25cc8e245284a1f28cf51ce55 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 30 Oct 2018 00:22:32 +0100 Subject: [PATCH 115/238] remove yet another duplicate and drop the unused PdfJsOnly list --- .../Formats/Jpg/JpegDecoderTests.Images.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index 748abdb99a..40de25b30a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -44,22 +44,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Progressive.Bad.ExifUndefType, TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518, - TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, TestImages.Jpeg.Issues.DhtHasWrongLength624, TestImages.Jpeg.Issues.OrderedInterleavedProgressive723A, TestImages.Jpeg.Issues.OrderedInterleavedProgressive723B, TestImages.Jpeg.Issues.OrderedInterleavedProgressive723C }; - /// - /// Golang decoder is unable to decode these - /// - public static string[] PdfJsOnly = - { - TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518, - TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159 - }; - private static readonly Dictionary CustomToleranceValues = new Dictionary { From 28b990bd2e2f71f0e24b4ab3053c979b5dcaab92 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 31 Oct 2018 00:25:38 +0100 Subject: [PATCH 116/238] add some benchmark results --- .../Codecs/Jpeg/DecodeJpeg.cs | 6 +- .../Codecs/Jpeg/LoadResizeSave.cs | 49 ++++++++---- .../Codecs/MultiImageBenchmarkBase.cs | 2 +- .../ImageSharp.Benchmarks/Samplers/Resize.cs | 74 ++++++++++++++++--- 4 files changed, 100 insertions(+), 31 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs index 9b968e4db3..8eb1fdda6b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs @@ -14,13 +14,15 @@ using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { [Config(typeof(Config.ShortClr))] - public class DecodeJpeg : BenchmarkBase + public class DecodeJpeg { private byte[] jpegBytes; private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); - [Params(TestImages.Jpeg.Baseline.Jpeg420Exif, TestImages.Jpeg.Baseline.Calliphora)] + [Params(TestImages.Jpeg.Baseline.Jpeg420Exif + //, TestImages.Jpeg.Baseline.Calliphora + )] public string TestImage { get; set; } [GlobalSetup] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs index 77ed828ef1..d0d4d569af 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs @@ -15,7 +15,7 @@ using SixLabors.ImageSharp.Formats.Jpeg; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { [Config(typeof(Config.ShortClr))] - public class LoadResizeSave : BenchmarkBase + public class LoadResizeSave { private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); @@ -32,23 +32,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg public string TestImage { get; set; } [Params(false, true)] - public bool EnableParallelExecution { get; set; } + public bool ParallelExec { get; set; } [GlobalSetup] public void Setup() { this.configuration.MaxDegreeOfParallelism = - this.EnableParallelExecution ? Environment.ProcessorCount : 1; + this.ParallelExec ? Environment.ProcessorCount : 1; - if (this.sourceBytes == null) - { - this.sourceBytes = File.ReadAllBytes(this.TestImageFullPath); - } + this.sourceBytes = File.ReadAllBytes(this.TestImageFullPath); - if (this.destBytes == null) - { - this.destBytes = new byte[this.sourceBytes.Length]; - } + this.destBytes = new byte[this.sourceBytes.Length * 2]; } [Benchmark(Baseline = true)] @@ -59,12 +53,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg using (var source = SDImage.FromStream(sourceStream)) using (var destination = new Bitmap(source.Width / 4, source.Height / 4)) { - using (var graphics = Graphics.FromImage(destination)) + using (var g = Graphics.FromImage(destination)) { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.DrawImage(source, 0, 0, 400, 400); + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.DrawImage(source, 0, 0, 400, 400); } destination.Save(destStream, ImageFormat.Jpeg); @@ -82,5 +76,28 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg source.SaveAsJpeg(destStream); } } + + // RESULTS: + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-ZPEZGV : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-SGOCJT : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | Runtime | TestImage | ParallelExec | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // -------------- |-------- |----------------------------- |------------- |----------:|----------:|----------:|-------:|---------:|---------:|----------:| + // SystemDrawing | Clr | Jpg/baseline/jpeg420exif.jpg | False | 64.88 ms | 3.735 ms | 0.2110 ms | 1.00 | 0.00 | 250.0000 | 791.07 KB | + // ImageSharp | Clr | Jpg/baseline/jpeg420exif.jpg | False | 129.53 ms | 23.423 ms | 1.3234 ms | 2.00 | 0.02 | - | 50.09 KB | + // | | | | | | | | | | | + // SystemDrawing | Core | Jpg/baseline/jpeg420exif.jpg | False | 65.87 ms | 10.488 ms | 0.5926 ms | 1.00 | 0.00 | 250.0000 | 789.79 KB | + // ImageSharp | Core | Jpg/baseline/jpeg420exif.jpg | False | 92.00 ms | 7.241 ms | 0.4091 ms | 1.40 | 0.01 | - | 46.36 KB | + // | | | | | | | | | | | + // SystemDrawing | Clr | Jpg/baseline/jpeg420exif.jpg | True | 64.23 ms | 5.998 ms | 0.3389 ms | 1.00 | 0.00 | 250.0000 | 791.07 KB | + // ImageSharp | Clr | Jpg/baseline/jpeg420exif.jpg | True | 82.63 ms | 29.320 ms | 1.6566 ms | 1.29 | 0.02 | - | 57.59 KB | + // | | | | | | | | | | | + // SystemDrawing | Core | Jpg/baseline/jpeg420exif.jpg | True | 64.20 ms | 6.560 ms | 0.3707 ms | 1.00 | 0.00 | 250.0000 | 789.79 KB | + // ImageSharp | Core | Jpg/baseline/jpeg420exif.jpg | True | 68.08 ms | 18.376 ms | 1.0383 ms | 1.06 | 0.01 | - | 50.49 KB | } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index f046f3033b..608d3604f9 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs using CoreImage = ImageSharp.Image; - public abstract class MultiImageBenchmarkBase : BenchmarkBase + public abstract class MultiImageBenchmarkBase { protected Dictionary FileNamesToBytes = new Dictionary(); diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index f53061d4e1..2be892295e 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -22,15 +22,17 @@ namespace SixLabors.ImageSharp.Benchmarks private Bitmap sourceBitmap; - public const int SourceSize = 3032; + [Params(3032)] + public int SourceSize { get; set; } - public const int DestSize = 400; + [Params(400)] + public int DestSize { get; set; } [GlobalSetup] public void Setup() { - this.sourceImage = new Image(this.Configuration, SourceSize, SourceSize); - this.sourceBitmap = new Bitmap(SourceSize, SourceSize); + this.sourceImage = new Image(this.Configuration, this.SourceSize, this.SourceSize); + this.sourceBitmap = new Bitmap(this.SourceSize, this.SourceSize); } [GlobalCleanup] @@ -43,14 +45,17 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Baseline = true)] public int SystemDrawing() { - using (var destination = new Bitmap(DestSize, DestSize)) + using (var destination = new Bitmap(this.DestSize, this.DestSize)) { - using (var graphics = Graphics.FromImage(destination)) + using (var g = Graphics.FromImage(destination)) { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.DrawImage(this.sourceBitmap, 0, 0, DestSize, DestSize); + g.CompositingMode = CompositingMode.SourceCopy; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.SmoothingMode = SmoothingMode.HighQuality; + + g.DrawImage(this.sourceBitmap, 0, 0, this.DestSize, this.DestSize); } return destination.Width; @@ -83,15 +88,60 @@ namespace SixLabors.ImageSharp.Benchmarks { protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { - ctx.Resize(DestSize, DestSize, KnownResamplers.Bicubic); + ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic); } + + // RESULTS: + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-IGUFBA : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-DZFERG : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | Runtime | SourceSize | DestSize | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------- |-------- |----------- |--------- |----------:|----------:|----------:|-------:|---------:|----------:| + // SystemDrawing | Clr | 3032 | 400 | 101.13 ms | 18.659 ms | 1.0542 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Clr | 3032 | 400 | 122.05 ms | 19.622 ms | 1.1087 ms | 1.21 | 0.01 | 21856 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Clr | 3032 | 400 | 41.34 ms | 54.841 ms | 3.0986 ms | 0.41 | 0.03 | 28000 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Clr | 3032 | 400 | 31.68 ms | 12.782 ms | 0.7222 ms | 0.31 | 0.01 | 28256 B | + // | | | | | | | | | | + // SystemDrawing | Core | 3032 | 400 | 100.37 ms | 18.479 ms | 1.0441 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | 3032 | 400 | 73.03 ms | 10.540 ms | 0.5955 ms | 0.73 | 0.01 | 21368 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Core | 3032 | 400 | 22.59 ms | 4.863 ms | 0.2748 ms | 0.23 | 0.00 | 25220 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Core | 3032 | 400 | 21.10 ms | 23.362 ms | 1.3200 ms | 0.21 | 0.01 | 25539 B | + } public class Resize_BicubicCompand : ResizeBenchmarkBase { protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { - ctx.Resize(DestSize, DestSize, KnownResamplers.Bicubic, true); + ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic, true); } + + // RESULTS: + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-IGUFBA : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-DZFERG : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | Runtime | SourceSize | DestSize | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------- |-------- |----------- |--------- |----------:|----------:|----------:|-------:|---------:|----------:| + // SystemDrawing | Clr | 3032 | 400 | 100.63 ms | 13.864 ms | 0.7833 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Clr | 3032 | 400 | 156.83 ms | 28.631 ms | 1.6177 ms | 1.56 | 0.02 | 21856 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Clr | 3032 | 400 | 53.43 ms | 38.493 ms | 2.1749 ms | 0.53 | 0.02 | 28512 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Clr | 3032 | 400 | 38.47 ms | 11.969 ms | 0.6763 ms | 0.38 | 0.01 | 28000 B | + // | | | | | | | | | | + // SystemDrawing | Core | 3032 | 400 | 99.87 ms | 23.459 ms | 1.3255 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | 3032 | 400 | 108.19 ms | 38.562 ms | 2.1788 ms | 1.08 | 0.02 | 21368 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Core | 3032 | 400 | 36.21 ms | 53.802 ms | 3.0399 ms | 0.36 | 0.03 | 25300 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Core | 3032 | 400 | 26.52 ms | 2.173 ms | 0.1228 ms | 0.27 | 0.00 | 25589 B | } } From b798d8dc014a3fbb6b074a11d2137ba00404a754 Mon Sep 17 00:00:00 2001 From: Devedse Date: Wed, 31 Oct 2018 00:41:07 +0100 Subject: [PATCH 117/238] Work in progress preserving isTrans data --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 97 ++++++++------------ src/ImageSharp/Formats/Png/PngEncoderCore.cs | 5 + src/ImageSharp/Formats/Png/PngMetaData.cs | 27 ++++++ src/ImageSharp/MetaData/ImageMetaData.cs | 1 + 4 files changed, 73 insertions(+), 57 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 11c4d831b0..024bd62216 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -124,31 +124,6 @@ namespace SixLabors.ImageSharp.Formats.Png ///
private PngColorType pngColorType; - /// - /// Represents any color in an 8 bit Rgb24 encoded png that should be transparent - /// - private Rgb24 rgb24Trans; - - /// - /// Represents any color in a 16 bit Rgb24 encoded png that should be transparent - /// - private Rgb48 rgb48Trans; - - /// - /// Represents any color in an 8 bit grayscale encoded png that should be transparent - /// - private byte luminanceTrans; - - /// - /// Represents any color in a 16 bit grayscale encoded png that should be transparent - /// - private ushort luminance16Trans; - - /// - /// Whether the image has transparency chunk and markers were decoded - /// - private bool hasTrans; - /// /// The next chunk of data to return /// @@ -213,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Png using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk)) { deframeStream.AllocateNewBytes(chunk.Length); - this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); + this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame, pngMetaData); } break; @@ -226,7 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Png byte[] alpha = new byte[chunk.Length]; Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); this.paletteAlpha = alpha; - this.AssignTransparentMarkers(alpha); + this.AssignTransparentMarkers(alpha, pngMetaData); break; case PngChunkType.Text: this.ReadTextChunk(metaData, chunk.Data.Array.AsSpan(0, chunk.Length)); @@ -331,7 +306,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset) - => (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); + { + return (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); + } /// /// Attempts to convert a byte array to a new array where each value in the original array is represented by the @@ -496,16 +473,17 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The containing data. /// The pixel data. - private void ReadScanlines(Stream dataStream, ImageFrame image) + /// The png meta data + private void ReadScanlines(Stream dataStream, ImageFrame image, PngMetaData pngMetaData) where TPixel : struct, IPixel { if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) { - this.DecodeInterlacedPixelData(dataStream, image); + this.DecodeInterlacedPixelData(dataStream, image, pngMetaData); } else { - this.DecodePixelData(dataStream, image); + this.DecodePixelData(dataStream, image, pngMetaData); } } @@ -515,7 +493,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The compressed pixel data stream. /// The image to decode to. - private void DecodePixelData(Stream compressedStream, ImageFrame image) + /// The png meta data + private void DecodePixelData(Stream compressedStream, ImageFrame image, PngMetaData pngMetaData) where TPixel : struct, IPixel { while (this.currentRow < this.header.Height) @@ -555,7 +534,7 @@ namespace SixLabors.ImageSharp.Formats.Png throw new ImageFormatException("Unknown filter type."); } - this.ProcessDefilteredScanline(scanlineSpan, image); + this.ProcessDefilteredScanline(scanlineSpan, image, pngMetaData); this.SwapBuffers(); this.currentRow++; @@ -569,7 +548,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The compressed pixel data stream. /// The current image. - private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image) + /// The png meta data + private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image, PngMetaData pngMetaData) where TPixel : struct, IPixel { while (true) @@ -626,7 +606,7 @@ namespace SixLabors.ImageSharp.Formats.Png } Span rowSpan = image.GetPixelRowSpan(this.currentRow); - this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, Adam7.FirstColumn[this.pass], Adam7.ColumnIncrement[this.pass]); + this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, pngMetaData, Adam7.FirstColumn[this.pass], Adam7.ColumnIncrement[this.pass]); this.SwapBuffers(); @@ -654,7 +634,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The de-filtered scanline /// The image - private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels) + /// The png meta data + private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels, PngMetaData pngMetaData) where TPixel : struct, IPixel { Span rowSpan = pixels.GetPixelRowSpan(this.currentRow); @@ -674,9 +655,9 @@ namespace SixLabors.ImageSharp.Formats.Png this.header, scanlineSpan, rowSpan, - this.hasTrans, - this.luminance16Trans, - this.luminanceTrans); + pngMetaData.HasTrans, + pngMetaData.Luminance16Trans, + pngMetaData.LuminanceTrans); break; @@ -708,9 +689,9 @@ namespace SixLabors.ImageSharp.Formats.Png rowSpan, this.bytesPerPixel, this.bytesPerSample, - this.hasTrans, - this.rgb48Trans, - this.rgb24Trans); + pngMetaData.HasTrans, + pngMetaData.Rgb48Trans, + pngMetaData.Rgb24Trans); break; @@ -735,9 +716,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The de-filtered scanline /// The current image row. + /// The png meta data /// The column start index. Always 0 for none interlaced images. /// The column increment. Always 1 for none interlaced images. - private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, int pixelOffset = 0, int increment = 1) + private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, PngMetaData pngMetaData, int pixelOffset = 0, int increment = 1) where TPixel : struct, IPixel { // Trim the first marker byte from the buffer @@ -757,9 +739,9 @@ namespace SixLabors.ImageSharp.Formats.Png rowSpan, pixelOffset, increment, - this.hasTrans, - this.luminance16Trans, - this.luminanceTrans); + pngMetaData.HasTrans, + pngMetaData.Luminance16Trans, + pngMetaData.LuminanceTrans); break; @@ -796,9 +778,9 @@ namespace SixLabors.ImageSharp.Formats.Png increment, this.bytesPerPixel, this.bytesPerSample, - this.hasTrans, - this.rgb48Trans, - this.rgb24Trans); + pngMetaData.HasTrans, + pngMetaData.Rgb48Trans, + pngMetaData.Rgb24Trans); break; @@ -822,7 +804,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// Decodes and assigns marker colors that identify transparent pixels in non indexed images /// /// The alpha tRNS array - private void AssignTransparentMarkers(ReadOnlySpan alpha) + /// The png meta data + private void AssignTransparentMarkers(ReadOnlySpan alpha, PngMetaData pngMetaData) { if (this.pngColorType == PngColorType.Rgb) { @@ -834,16 +817,16 @@ namespace SixLabors.ImageSharp.Formats.Png ushort gc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(2, 2)); ushort bc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(4, 2)); - this.rgb48Trans = new Rgb48(rc, gc, bc); - this.hasTrans = true; + pngMetaData.Rgb48Trans = new Rgb48(rc, gc, bc); + pngMetaData.HasTrans = true; return; } byte r = ReadByteLittleEndian(alpha, 0); byte g = ReadByteLittleEndian(alpha, 2); byte b = ReadByteLittleEndian(alpha, 4); - this.rgb24Trans = new Rgb24(r, g, b); - this.hasTrans = true; + pngMetaData.Rgb24Trans = new Rgb24(r, g, b); + pngMetaData.HasTrans = true; } } else if (this.pngColorType == PngColorType.Grayscale) @@ -852,14 +835,14 @@ namespace SixLabors.ImageSharp.Formats.Png { if (this.header.BitDepth == 16) { - this.luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); + pngMetaData.Luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); } else { - this.luminanceTrans = ReadByteLittleEndian(alpha, 0); + pngMetaData.LuminanceTrans = ReadByteLittleEndian(alpha, 0); } - this.hasTrans = true; + pngMetaData.HasTrans = true; } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7ae716aa05..411d5d69b2 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -290,6 +290,11 @@ namespace SixLabors.ImageSharp.Formats.Png this.WritePaletteChunk(stream, quantized); } + if (pngMetaData.HasTrans) + { + //Write transparency header + } + this.WritePhysicalChunk(stream, metaData); this.WriteGammaChunk(stream); this.WriteExifChunk(stream, metaData); diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 9c76765146..0014defbb9 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp.Formats.Png { /// @@ -42,6 +44,31 @@ namespace SixLabors.ImageSharp.Formats.Png /// public float Gamma { get; set; } + /// + /// Gets or sets the Rgb 24 transparent color. This represents any color in an 8 bit Rgb24 encoded png that should be transparent + /// + public Rgb24 Rgb24Trans { get; set; } + + /// + /// Gets or sets the Rgb 48 transparent color. This represents any color in a 16 bit Rgb24 encoded png that should be transparent + /// + public Rgb48 Rgb48Trans { get; set; } + + /// + /// Gets or sets the 8 bit grayscale transparent color. This represents any color in an 8 bit grayscale encoded png that should be transparent + /// + public byte LuminanceTrans { get; set; } + + /// + /// Gets or sets the 16 bit grayscale transparent color. This represents any color in a 16 bit grayscale encoded png that should be transparent + /// + public ushort Luminance16Trans { get; set; } + + /// + /// Gets or sets a value indicating whether the image has transparency chunk and markers were decoded + /// + public bool HasTrans { get; set; } + /// public IDeepCloneable DeepClone() => new PngMetaData(this); } diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 73549d98aa..ec9037479b 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Icc; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.MetaData { From 068b2d3d1ce4ee98546d0be15c79043f46a2ee95 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 31 Oct 2018 00:54:40 +0100 Subject: [PATCH 118/238] results for DecodeJpeg --- .../Codecs/Jpeg/DecodeJpeg.cs | 19 +++++++++++++++++++ .../Codecs/Jpeg/LoadResizeSave.cs | 3 ++- .../ImageSharp.Benchmarks/Samplers/Resize.cs | 4 ++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs index 8eb1fdda6b..2afacb1e4f 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs @@ -57,5 +57,24 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } } } + + // RESULTS (2018 October): + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-MCUBGX : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-TZIRPF : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // + // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| + // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.10 ms | 4.720 ms | 0.2667 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | + // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 57.77 ms | 4.626 ms | 0.2614 ms | 3.38 | 0.04 | 125.0000 | 566.01 KB | + // | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs index d0d4d569af..72062fc7da 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs @@ -77,7 +77,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } } - // RESULTS: + // RESULTS (2018 October): + // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index 2be892295e..148b253281 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Benchmarks ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic); } - // RESULTS: + // RESULTS (2018 October): // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Benchmarks ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic, true); } - // RESULTS: + // RESULTS (2018 October): // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores From e65fc5481f1617de7076f3ced7b54803633e772a Mon Sep 17 00:00:00 2001 From: Devedse Date: Wed, 31 Oct 2018 01:14:09 +0100 Subject: [PATCH 119/238] This should write transparency --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 16 +++--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 56 ++++++++++++++++++-- src/ImageSharp/Formats/Png/PngMetaData.cs | 8 +-- 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 024bd62216..87c22a2ad6 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -656,8 +656,8 @@ namespace SixLabors.ImageSharp.Formats.Png scanlineSpan, rowSpan, pngMetaData.HasTrans, - pngMetaData.Luminance16Trans, - pngMetaData.LuminanceTrans); + pngMetaData.Luminance16Trans.GetValueOrDefault(), + pngMetaData.LuminanceTrans.GetValueOrDefault()); break; @@ -690,8 +690,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerPixel, this.bytesPerSample, pngMetaData.HasTrans, - pngMetaData.Rgb48Trans, - pngMetaData.Rgb24Trans); + pngMetaData.Rgb48Trans.GetValueOrDefault(), + pngMetaData.Rgb24Trans.GetValueOrDefault()); break; @@ -740,8 +740,8 @@ namespace SixLabors.ImageSharp.Formats.Png pixelOffset, increment, pngMetaData.HasTrans, - pngMetaData.Luminance16Trans, - pngMetaData.LuminanceTrans); + pngMetaData.Luminance16Trans.GetValueOrDefault(), + pngMetaData.LuminanceTrans.GetValueOrDefault()); break; @@ -779,8 +779,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerPixel, this.bytesPerSample, pngMetaData.HasTrans, - pngMetaData.Rgb48Trans, - pngMetaData.Rgb24Trans); + pngMetaData.Rgb48Trans.GetValueOrDefault(), + pngMetaData.Rgb24Trans.GetValueOrDefault()); break; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 411d5d69b2..c76dc308bc 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -292,7 +292,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (pngMetaData.HasTrans) { - //Write transparency header + this.WriteTransparencyMarkers(stream, pngMetaData); } this.WritePhysicalChunk(stream, metaData); @@ -305,6 +305,50 @@ namespace SixLabors.ImageSharp.Formats.Png quantized?.Dispose(); } + /// + /// Writes the transparency markers to the stream + /// + /// The containing image data. + /// The image meta data. + private void WriteTransparencyMarkers(Stream stream, PngMetaData pngMetaData) + { + if (pngMetaData.ColorType == PngColorType.Rgb) + { + if (pngMetaData.Rgb48Trans != null) + { + var r = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); + var g = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); + var B = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.B); + + var alphaArray = r.Concat(g).Concat(B).ToArray(); + + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); + } + else if (pngMetaData.Rgb24Trans != null) + { + var alphaArray = new byte[6]; + alphaArray[0] = pngMetaData.Rgb24Trans.Value.R; + alphaArray[2] = pngMetaData.Rgb24Trans.Value.G; + alphaArray[4] = pngMetaData.Rgb24Trans.Value.B; + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); + } + } + else if (pngMetaData.ColorType == PngColorType.Grayscale) + { + if (pngMetaData.Luminance16Trans != null) + { + var alphaArray = BitConverter.GetBytes(pngMetaData.Luminance16Trans.Value); + + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); + } + else if (pngMetaData.LuminanceTrans != null) + { + var alphaArray = new byte[2]; + alphaArray[0] = pngMetaData.LuminanceTrans.Value; + } + } + } + /// public void Dispose() { @@ -848,7 +892,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// Writes the chunk end to the stream. ///
/// The containing image data. - private void WriteEndChunk(Stream stream) => this.WriteChunk(stream, PngChunkType.End, null); + private void WriteEndChunk(Stream stream) + { + this.WriteChunk(stream, PngChunkType.End, null); + } /// /// Writes a chunk to the stream. @@ -856,7 +903,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// The to write to. /// The type of chunk to write. /// The containing data. - private void WriteChunk(Stream stream, PngChunkType type, byte[] data) => this.WriteChunk(stream, type, data, 0, data?.Length ?? 0); + private void WriteChunk(Stream stream, PngChunkType type, byte[] data) + { + this.WriteChunk(stream, type, data, 0, data?.Length ?? 0); + } /// /// Writes a chunk of a specified length to the stream at the given offset. diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 0014defbb9..765222795a 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -47,22 +47,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets or sets the Rgb 24 transparent color. This represents any color in an 8 bit Rgb24 encoded png that should be transparent /// - public Rgb24 Rgb24Trans { get; set; } + public Rgb24? Rgb24Trans { get; set; } /// /// Gets or sets the Rgb 48 transparent color. This represents any color in a 16 bit Rgb24 encoded png that should be transparent /// - public Rgb48 Rgb48Trans { get; set; } + public Rgb48? Rgb48Trans { get; set; } /// /// Gets or sets the 8 bit grayscale transparent color. This represents any color in an 8 bit grayscale encoded png that should be transparent /// - public byte LuminanceTrans { get; set; } + public byte? LuminanceTrans { get; set; } /// /// Gets or sets the 16 bit grayscale transparent color. This represents any color in a 16 bit grayscale encoded png that should be transparent /// - public ushort Luminance16Trans { get; set; } + public ushort? Luminance16Trans { get; set; } /// /// Gets or sets a value indicating whether the image has transparency chunk and markers were decoded From fae06caff766697f82807aed30b4c5fe623b2b39 Mon Sep 17 00:00:00 2001 From: Devedse Date: Wed, 31 Oct 2018 01:27:11 +0100 Subject: [PATCH 120/238] Fixed bug, code now actually fixed my unit test --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index c76dc308bc..edf6cecd7a 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -327,9 +327,9 @@ namespace SixLabors.ImageSharp.Formats.Png else if (pngMetaData.Rgb24Trans != null) { var alphaArray = new byte[6]; - alphaArray[0] = pngMetaData.Rgb24Trans.Value.R; - alphaArray[2] = pngMetaData.Rgb24Trans.Value.G; - alphaArray[4] = pngMetaData.Rgb24Trans.Value.B; + alphaArray[1] = pngMetaData.Rgb24Trans.Value.R; + alphaArray[3] = pngMetaData.Rgb24Trans.Value.G; + alphaArray[5] = pngMetaData.Rgb24Trans.Value.B; this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } } @@ -344,7 +344,9 @@ namespace SixLabors.ImageSharp.Formats.Png else if (pngMetaData.LuminanceTrans != null) { var alphaArray = new byte[2]; - alphaArray[0] = pngMetaData.LuminanceTrans.Value; + alphaArray[1] = pngMetaData.LuminanceTrans.Value; + + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } } } From 099e38a57ba142143d68ac9478534dd60b192ae7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 31 Oct 2018 01:29:10 +0100 Subject: [PATCH 121/238] drop ComplexIntegrationTests, add ProfilingBenchmarks --- .../ComplexIntegrationTests.cs | 35 ------------- tests/ImageSharp.Tests/ProfilingBenchmarks.cs | 52 +++++++++++++++++++ 2 files changed, 52 insertions(+), 35 deletions(-) delete mode 100644 tests/ImageSharp.Tests/ComplexIntegrationTests.cs create mode 100644 tests/ImageSharp.Tests/ProfilingBenchmarks.cs diff --git a/tests/ImageSharp.Tests/ComplexIntegrationTests.cs b/tests/ImageSharp.Tests/ComplexIntegrationTests.cs deleted file mode 100644 index a260ec33ca..0000000000 --- a/tests/ImageSharp.Tests/ComplexIntegrationTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.Primitives; - -using Xunit; - -namespace SixLabors.ImageSharp.Tests -{ - /// - /// Might be useful to catch complex bugs - /// - public class ComplexIntegrationTests - { - [Theory] - [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] - [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] - [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] - [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] - public void LoadResizeSave(TestImageProvider provider, int quality, JpegSubsample subsample) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage(x => x.Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max }))) - { - - image.MetaData.ExifProfile = null; // Reduce the size of the file - JpegEncoder options = new JpegEncoder { Subsample = subsample, Quality = quality }; - - provider.Utility.TestName += $"{subsample}_Q{quality}"; - provider.Utility.SaveTestOutputFile(image, "png"); - provider.Utility.SaveTestOutputFile(image, "jpg", options); - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks.cs new file mode 100644 index 0000000000..fa873ef859 --- /dev/null +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks.cs @@ -0,0 +1,52 @@ +using System.IO; + +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests +{ + public class ProfilingBenchmarks : MeasureFixture + { + public const string SkipProfilingTests = +#if false + null; +#else + "Profiling benchmark, enable manually!"; +#endif + + + public ProfilingBenchmarks(ITestOutputHelper output) + : base(output) + { + } + + [Theory(Skip = SkipProfilingTests)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)] + public void LoadResizeSave(string imagePath) + { + var configuration = Configuration.CreateDefaultInstance(); + configuration.MaxDegreeOfParallelism = 1; + + byte[] imageBytes = TestFile.Create(imagePath).Bytes; + + using (var ms = new MemoryStream()) + { + this.Measure(30, + () => + { + using (var image = Image.Load(configuration, imageBytes)) + { + image.Mutate(x => x.Resize(image.Size() / 4)); + image.SaveAsJpeg(ms); + } + ms.Seek(0, SeekOrigin.Begin); + }); + } + } + } +} \ No newline at end of file From bd4b78544fa22834221476830fd393514fd40060 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 31 Oct 2018 01:34:13 +0100 Subject: [PATCH 122/238] use InliningOptions.ShortMethod --- .../Formats/Jpeg/Components/Block8x8F.cs | 30 +++++++++---------- .../Jpeg/Components/Decoder/ScanDecoder.cs | 2 +- .../Formats/Jpeg/JpegDecoderCore.cs | 4 +-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 59fc234c42..3a912dc62b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// The float value at the specified index public float this[int idx] { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get { GuardBlockIndex(idx); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return Unsafe.Add(ref selfRef, idx); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set { GuardBlockIndex(idx); @@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Fill the block with defaults (zeroes) /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void Clear() { // The cheapest way to do this in C#: @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Load raw 32bit floating point data from source /// /// Source - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void LoadFrom(Span source) { ref byte s = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Block pointer /// Source - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void LoadFrom(Block8x8F* blockPtr, Span source) { blockPtr->LoadFrom(source); @@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy raw 32bit floating point data to dest /// /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void CopyTo(Span dest) { ref byte d = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components ///
/// Pointer to block /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest) { float* fPtr = (float*)blockPtr; @@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components ///
/// Block pointer /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest) { blockPtr->CopyTo(dest); @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy raw 32bit floating point data to dest ///
/// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public unsafe void CopyTo(float[] dest) { fixed (void* ptr = &this.V0L) @@ -276,7 +276,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Multiply all elements of the block. ///
/// The value to multiply by - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void MultiplyInplace(float value) { this.V0L *= value; @@ -300,7 +300,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Multiply all elements of the block by the corresponding elements of 'other' /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void MultiplyInplace(ref Block8x8F other) { this.V0L *= other.V0L; @@ -325,7 +325,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Adds a vector to all elements of the block. ///
/// The added vector - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void AddToAllInplace(Vector4 diff) { this.V0L += diff; @@ -420,7 +420,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static void DivideRoundAll(ref Block8x8F a, ref Block8x8F b) { a.V0L = DivideRound(a.V0L, b.V0L); @@ -511,7 +511,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return sb.ToString(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Vector NormalizeAndRound(Vector row, Vector off, Vector max) { row += off; @@ -520,7 +520,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return row.FastRound(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor) { // sign(dividend) = max(min(dividend, 1), -1) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index 351e453484..39b9792ac9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static uint LRot(uint x, int y) => (x << y) | (x >> (32 - y)); private void ParseBaselineData() diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 36246c6820..68252f624c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -913,7 +913,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The table index /// The codelengths /// The values - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void BuildHuffmanTable(HuffmanTables tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) => tables[index] = new HuffmanTable(this.configuration.MemoryAllocator, codeLengths, values); @@ -921,7 +921,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// Reads a from the stream advancing it by two bytes ///
/// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private ushort ReadUint16() { this.InputStream.Read(this.markerBuffer, 0, 2); From 02a8d0ddc185979175a4af170bc43e88bc493807 Mon Sep 17 00:00:00 2001 From: Devedse <2350015+devedse@users.noreply.github.com> Date: Wed, 31 Oct 2018 02:04:59 +0100 Subject: [PATCH 123/238] Update PngEncoderCore.cs Lowercase b --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index edf6cecd7a..1179a6db31 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -318,9 +318,9 @@ namespace SixLabors.ImageSharp.Formats.Png { var r = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); var g = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); - var B = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.B); + var b = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.B); - var alphaArray = r.Concat(g).Concat(B).ToArray(); + var alphaArray = r.Concat(g).Concat(b).ToArray(); this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } @@ -1004,4 +1004,4 @@ namespace SixLabors.ImageSharp.Formats.Png return scanlineLength / mod; } } -} \ No newline at end of file +} From b2920a12ba89334acf20d3f89865cc0ac66753bc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 31 Oct 2018 18:00:11 +0000 Subject: [PATCH 124/238] Don't force transparency --- .../PixelFormats/NamedColors{TPixel}.cs | 5 +--- src/ImageSharp/Processing/KnownQuantizers.cs | 4 --- .../Quantization/QuantizedImageTests.cs | 25 ------------------- tests/Images/External | 2 +- 4 files changed, 2 insertions(+), 34 deletions(-) diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index a757a393ef..7e093de042 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -746,10 +746,7 @@ namespace SixLabors.ImageSharp.PixelFormats private static TPixel[] GetPalette(Rgba32[] palette) { - // TODO: This should be the length only. - // We need to fix and update tests/reference images. - // If someone wants transparency they should add it to the palette. - var converted = new TPixel[palette.Length + 1]; + var converted = new TPixel[palette.Length]; Span constantsBytes = MemoryMarshal.Cast(palette.AsSpan()); PixelOperations.Instance.FromRgba32Bytes( diff --git a/src/ImageSharp/Processing/KnownQuantizers.cs b/src/ImageSharp/Processing/KnownQuantizers.cs index e93a9921a9..e4a7a75d5f 100644 --- a/src/ImageSharp/Processing/KnownQuantizers.cs +++ b/src/ImageSharp/Processing/KnownQuantizers.cs @@ -12,26 +12,22 @@ namespace SixLabors.ImageSharp.Processing { /// /// Gets the adaptive Octree quantizer. Fast with good quality. - /// The quantizer only supports a single alpha value. /// public static IQuantizer Octree { get; } = new OctreeQuantizer(); /// /// Gets the Xiaolin Wu's Color Quantizer which generates high quality output. - /// The quantizer supports multiple alpha values. /// public static IQuantizer Wu { get; } = new WuQuantizer(); /// /// Gets the palette based quantizer consisting of web safe colors as defined in the CSS Color Module Level 4. - /// The quantizer supports a single alpha value. /// public static IQuantizer WebSafe { get; } = new WebSafePaletteQuantizer(); /// /// Gets the palette based quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. /// The hex codes were collected and defined by Nicholas Rougeux - /// The quantizer supports a single alpha value. /// public static IQuantizer Werner { get; } = new WernerPaletteQuantizer(); } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 753c2c109c..a0d7869e39 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -31,31 +31,6 @@ namespace SixLabors.ImageSharp.Tests Assert.True(wu.CreateFrameQuantizer(this.Configuration).Dither); } - [Theory] - [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] - [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void PaletteQuantizerYieldsCorrectTransparentPixel( - TestImageProvider provider, - bool dither) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage()) - { - Assert.True(image[0, 0].Equals(default(TPixel))); - - var quantizer = new WebSafePaletteQuantizer(dither); - - foreach (ImageFrame frame in image.Frames) - { - QuantizedFrame quantized = - quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); - - int index = this.GetTransparentIndex(quantized); - Assert.Equal(index, quantized.GetPixelSpan()[0]); - } - } - } - [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] diff --git a/tests/Images/External b/tests/Images/External index f41ae0327a..ed8a7b0b6f 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit f41ae0327a3ab21ab2388c32160bda67debcc082 +Subproject commit ed8a7b0b6fe1b2e2a7c822aa617103ae31192655 From b5e419d89ee76ee256822273068a70978f181124 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 1 Nov 2018 14:16:53 +0100 Subject: [PATCH 125/238] InliningOptions.ShortMethod --- .../Formats/Jpeg/Components/Block8x8F.Generated.cs | 4 ++-- .../Formats/Jpeg/Components/Block8x8F.Generated.tt | 4 ++-- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index e83896f587..53f29734c5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Transpose the block into the destination block. ///
/// The destination block - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void TransposeInto(ref Block8x8F d) { d.V0L.X = V0L.X; @@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// AVX2-only variant for executing and in one step. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void NormalizeColorsAndRoundInplaceAvx2() { Vector off = new Vector(128f); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index 82d82ef0c2..76c61f6c35 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Transpose the block into the destination block. ///
/// The destination block - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void TransposeInto(ref Block8x8F d) { <# @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// AVX2-only variant for executing and in one step. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void NormalizeColorsAndRoundInplaceAvx2() { Vector off = new Vector(128f); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index 32538090dc..f60f478e1a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -24,21 +24,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public static readonly TheoryData DecodeJpegData = new TheoryData() { - TestImages.Jpeg.Baseline.Cmyk, - TestImages.Jpeg.Baseline.Ycck, + //TestImages.Jpeg.Baseline.Cmyk, + //TestImages.Jpeg.Baseline.Ycck, TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Jpeg400, TestImages.Jpeg.Baseline.Jpeg420Exif, TestImages.Jpeg.Baseline.Jpeg444, }; - // [Theory] // Benchmark, enable manually - // [MemberData(nameof(DecodeJpegData))] + [Theory] // Benchmark, enable manually + [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); } - + private void DecodeJpegBenchmarkImpl(string fileName, IImageDecoder decoder) { // do not run this on CI even by accident From af5e0138d5c0cd649b5f57e0c374bfbcf6b6a5d2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 1 Nov 2018 14:21:42 +0000 Subject: [PATCH 126/238] Change tolerance for Net462 --- tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index a98ae164a1..b74a7a85f9 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif public class GifEncoderTests { private const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.RgbaVector | PixelTypes.Argb32; - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.001F); + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0015F); public static readonly TheoryData RatioFiles = new TheoryData From 7f113ab00a03bca62b48499db366d17f68809f4d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 1 Nov 2018 16:00:17 +0100 Subject: [PATCH 127/238] AVX2 optimized Block8x8 -> Block8x8F conversion --- src/ImageSharp/Common/Helpers/DebugGuard.cs | 14 ++++++ .../Common/Helpers/InliningOptions.cs | 2 +- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 14 ++++++ .../Jpeg/Components/Block8x8F.Generated.cs | 2 +- .../Jpeg/Components/Block8x8F.Generated.tt | 2 +- .../Formats/Jpeg/Components/Block8x8F.cs | 45 +++++++++++++++++++ .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 21 +++++++++ .../Formats/Jpg/Block8x8FTests.cs | 42 +++++++++++++++++ .../Formats/Jpg/JpegProfilingBenchmarks.cs | 4 +- .../Formats/Jpg/Utils/JpegFixture.cs | 7 ++- tests/ImageSharp.Tests/ProfilingBenchmarks.cs | 2 +- .../TestUtilities/TestDataGenerator.cs | 11 +++++ 12 files changed, 159 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs index 2cf18b2456..43eebeac87 100644 --- a/src/ImageSharp/Common/Helpers/DebugGuard.cs +++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs @@ -163,6 +163,20 @@ namespace SixLabors.ImageSharp } } + /// + /// Verifies whether a specific condition is met, throwing an exception if it's false. + /// + /// The condition + /// The error message + [Conditional("DEBUG")] + public static void IsTrue(bool target, string message) + { + if (!target) + { + throw new InvalidOperationException(message); + } + } + /// /// Verifies, that the method parameter with specified target value is false /// and throws an exception if it is found to be so. diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index ad85c4fc81..f61e4f8aef 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. // Uncomment this for verbose profiler results: -// #define PROFILING +#define PROFILING using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 2ac577264c..463961d868 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -25,6 +25,20 @@ namespace SixLabors.ImageSharp false; #endif + /// + /// Widen and convert a vector of values into 2 vectors of -s. + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ConvertToSingle( + Vector source, + out Vector dest1, + out Vector dest2) + { + Vector.Widen(source, out Vector i1, out Vector i2); + dest1 = Vector.ConvertToSingle(i1); + dest2 = Vector.ConvertToSingle(i2); + } + /// /// as many elements as possible, slicing them down (keeping the remainder). /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index 53f29734c5..09ed6408d7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Fill the block from 'source' doing short -> float conversion. /// - public void LoadFrom(ref Block8x8 source) + public void LoadFromInt16Scalar(ref Block8x8 source) { ref short selfRef = ref Unsafe.As(ref source); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index 76c61f6c35..f93ee6522d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Fill the block from 'source' doing short -> float conversion. /// - public void LoadFrom(ref Block8x8 source) + public void LoadFromInt16Scalar(ref Block8x8 source) { ref short selfRef = ref Unsafe.As(ref source); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 3a912dc62b..137a8029d8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -493,6 +493,51 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } } + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref Block8x8 source) + { +#if SUPPORTS_EXTENDED_INTRINSICS + if (SimdUtils.IsAvx2CompatibleArchitecture) + { + this.LoadFromInt16ExtendedAvx2(ref source); + return; + } +#endif + this.LoadFromInt16Scalar(ref source); + } + + /// + /// Loads values from using extended AVX2 intrinsics. + /// + /// The source + public void LoadFromInt16ExtendedAvx2(ref Block8x8 source) + { + DebugGuard.IsTrue( + SimdUtils.IsAvx2CompatibleArchitecture, + "LoadFromUInt16ExtendedAvx2 only works on AVX2 compatible architecture!"); + + ref Vector sRef = ref Unsafe.As>(ref source); + ref Vector dRef = ref Unsafe.As>(ref this); + + // Vector.Count == 16 on AVX2 + // We can process 2 block rows in a single step + SimdUtils.ExtendedIntrinsics.ConvertToSingle(sRef, out Vector top, out Vector bottom); + dRef = top; + Unsafe.Add(ref dRef, 1) = bottom; + + SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 1), out top, out bottom); + Unsafe.Add(ref dRef, 2) = top; + Unsafe.Add(ref dRef, 3) = bottom; + + SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 2), out top, out bottom); + Unsafe.Add(ref dRef, 4) = top; + Unsafe.Add(ref dRef, 5) = bottom; + + SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 3), out top, out bottom); + Unsafe.Add(ref dRef, 6) = top; + Unsafe.Add(ref dRef, 7) = bottom; + } + /// public override string ToString() { diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index c63cb3438f..4f8a2cdaf7 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -257,6 +257,27 @@ namespace SixLabors.ImageSharp.Tests.Common ); } + [Theory] + [InlineData(1234)] + public void ExtendedIntrinsics_ConvertToSingle(short scale) + { + int n = Vector.Count; + short[] sData = new Random(scale).GenerateRandomInt16Array(2 * n, (short)-scale, scale); + float[] fData = sData.Select(u => (float)u).ToArray(); + + var source = new Vector(sData); + + var expected1 = new Vector(fData, 0); + var expected2 = new Vector(fData, n); + + // Act: + SimdUtils.ExtendedIntrinsics.ConvertToSingle(source, out Vector actual1, out Vector actual2); + + // Assert: + Assert.Equal(expected1, actual1); + Assert.Equal(expected2, actual2); + } + [Theory] [MemberData(nameof(ArbitraryArraySizes))] public void BulkConvertNormalizedFloatToByteClampOverflows(int count) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs index e72f4945b7..81c76390c1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs @@ -408,5 +408,47 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(original[i] * 42f, actual[i]); } } + + [Fact] + public void LoadFromUInt16Scalar() + { + if (this.SkipOnNonAvx2Runner()) + { + return; + } + + short[] data = Create8x8ShortData(); + + var source = new Block8x8(data); + + Block8x8F dest = default; + dest.LoadFromInt16Scalar(ref source); + + for (int i = 0; i < Block8x8F.Size; i++) + { + Assert.Equal((float)data[i], dest[i]); + } + } + + [Fact] + public void LoadFromUInt16ExtendedAvx2() + { + if (this.SkipOnNonAvx2Runner()) + { + return; + } + + short[] data = Create8x8ShortData(); + + var source = new Block8x8(data); + + Block8x8F dest = default; + dest.LoadFromInt16ExtendedAvx2(ref source); + + for (int i = 0; i < Block8x8F.Size; i++) + { + Assert.Equal((float)data[i], dest[i]); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index f60f478e1a..7d5130e1bc 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -32,8 +32,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Jpeg444, }; - [Theory] // Benchmark, enable manually - [MemberData(nameof(DecodeJpegData))] + //[Theory] // Benchmark, enable manually + //[MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs index d14fbc3fc3..89fdd5745e 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs @@ -58,7 +58,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils { for (int j = 0; j < 8; j++) { - result[i * 8 + j] = (short)(i * 10 + j); + short val = (short)(i * 10 + j); + if ((i + j) % 2 == 0) + { + val *= -1; + } + result[i * 8 + j] = val; } } return result; diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks.cs index fa873ef859..bc9b2a947b 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests public class ProfilingBenchmarks : MeasureFixture { public const string SkipProfilingTests = -#if false +#if true null; #else "Profiling benchmark, enable manually!"; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 56cde41fc1..e3d8bf3806 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -88,6 +88,17 @@ namespace SixLabors.ImageSharp.Tests return values; } + public static short[] GenerateRandomInt16Array(this Random rnd, int length, short minVal, short maxVal) + { + short[] values = new short[length]; + for (int i = 0; i < values.Length; i++) + { + values[i] = (short)rnd.Next(minVal, maxVal); + } + + return values; + } + private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) => ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; } } \ No newline at end of file From 2acf80ea163a5eeb98daac9e5d9d6a4f0f6523ef Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 2 Nov 2018 00:36:04 +0100 Subject: [PATCH 128/238] Moved IJpegComponent.GetBlockReference(...) to an extension method --- .../Jpeg/Components/Decoder/IJpegComponent.cs | 11 +----- .../Jpeg/Components/Decoder/JpegComponent.cs | 18 ++------- .../Decoder/JpegComponentExtensions.cs | 39 +++++++++++++++++++ 3 files changed, 44 insertions(+), 24 deletions(-) create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs index c033980336..2492a985a8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder @@ -43,16 +42,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Gets the storing the "raw" frequency-domain decoded + unzigged blocks. - /// We need to apply IDCT and dequantiazition to transform them into color-space blocks. + /// We need to apply IDCT and dequantization to transform them into color-space blocks. /// Buffer2D SpectralBlocks { get; } - - /// - /// Gets a reference to the at the given row and column index from - /// - /// The column - /// The row - /// The - ref Block8x8 GetBlockReference(int column, int row); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs index 65a584c4f2..ef03582d69 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs @@ -128,21 +128,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors); } - this.SpectralBlocks = this.memoryAllocator.Allocate2D(blocksPerColumnForMcu, blocksPerLineForMcu + 1, AllocationOptions.Clean); - } + int totalNumberOfBlocks = blocksPerColumnForMcu * (blocksPerLineForMcu + 1); + int width = this.WidthInBlocks + 1; + int height = totalNumberOfBlocks / width; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref Block8x8 GetBlockReference(int column, int row) - { - int offset = ((this.WidthInBlocks + 1) * row) + column; - return ref Unsafe.Add(ref MemoryMarshal.GetReference(this.SpectralBlocks.GetSpan()), offset); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref short GetBlockDataReference(int column, int row) - { - ref Block8x8 blockRef = ref this.GetBlockReference(column, row); - return ref Unsafe.As(ref blockRef); + this.SpectralBlocks = this.memoryAllocator.Allocate2D(width, height, AllocationOptions.Clean); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs new file mode 100644 index 0000000000..d7fb52a790 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder +{ + /// + /// Extension methods for + /// + internal static class JpegComponentExtensions + { + /// + /// Gets a reference to the at the given row and column index from + /// + /// The + /// The column + /// The row + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static ref Block8x8 GetBlockReference(this IJpegComponent component, int column, int row) + { + return ref component.SpectralBlocks.GetRowSpan(row)[column]; + } + + /// + /// Gets a reference to the first item in a block + /// at the given row and column index from + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static ref short GetBlockDataReference(this IJpegComponent component, int column, int row) + { + ref Block8x8 blockRef = ref component.GetBlockReference(column, row); + return ref Unsafe.As(ref blockRef); + } + } +} \ No newline at end of file From aa35af70953503a95e6dbb0d16ab7b5b70935970 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 2 Nov 2018 00:45:25 +0100 Subject: [PATCH 129/238] do not use GetBlockReference() on hot path --- .../Decoder/JpegComponentPostProcessor.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs index 890f402595..57a53549f5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.Memory; @@ -88,12 +90,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int yBuffer = y * this.blockAreaSize.Height; - for (int x = 0; x < this.SizeInBlocks.Width; x++) - { - int xBlock = x; - int xBuffer = x * this.blockAreaSize.Width; + Span blockRow = this.Component.SpectralBlocks.GetRowSpan(yBlock); + + ref Block8x8 blockRowBase = ref MemoryMarshal.GetReference(blockRow); - ref Block8x8 block = ref this.Component.GetBlockReference(xBlock, yBlock); + for (int xBlock = 0; xBlock < this.SizeInBlocks.Width; xBlock++) + { + ref Block8x8 block = ref Unsafe.Add(ref blockRowBase, xBlock); + int xBuffer = xBlock * this.blockAreaSize.Width; BufferArea destArea = this.ColorBuffer.GetArea( xBuffer, From a7aef83dcceb7d291b7bed81277e675be2d65ca7 Mon Sep 17 00:00:00 2001 From: Devedse Date: Fri, 2 Nov 2018 17:36:38 +0100 Subject: [PATCH 130/238] Removed unused using --- src/ImageSharp/MetaData/ImageMetaData.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index ec9037479b..73549d98aa 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Icc; -using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.MetaData { From 6364b502da9aed140aa8430ccdddb148acf6efd3 Mon Sep 17 00:00:00 2001 From: Devedse Date: Fri, 2 Nov 2018 17:49:35 +0100 Subject: [PATCH 131/238] Resolved findings in PR --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 24 +++++++++---------- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 24 +++++++++---------- src/ImageSharp/Formats/Png/PngMetaData.cs | 8 +++---- .../Formats/Png/PngScanlineProcessor.cs | 16 ++++++------- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 87c22a2ad6..c446184d80 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -656,8 +656,8 @@ namespace SixLabors.ImageSharp.Formats.Png scanlineSpan, rowSpan, pngMetaData.HasTrans, - pngMetaData.Luminance16Trans.GetValueOrDefault(), - pngMetaData.LuminanceTrans.GetValueOrDefault()); + pngMetaData.TransparentGray16.GetValueOrDefault(), + pngMetaData.TransparentGray8.GetValueOrDefault()); break; @@ -690,8 +690,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerPixel, this.bytesPerSample, pngMetaData.HasTrans, - pngMetaData.Rgb48Trans.GetValueOrDefault(), - pngMetaData.Rgb24Trans.GetValueOrDefault()); + pngMetaData.TransparentRgb48.GetValueOrDefault(), + pngMetaData.TransparentRgb24.GetValueOrDefault()); break; @@ -740,8 +740,8 @@ namespace SixLabors.ImageSharp.Formats.Png pixelOffset, increment, pngMetaData.HasTrans, - pngMetaData.Luminance16Trans.GetValueOrDefault(), - pngMetaData.LuminanceTrans.GetValueOrDefault()); + pngMetaData.TransparentGray16.GetValueOrDefault(), + pngMetaData.TransparentGray8.GetValueOrDefault()); break; @@ -779,8 +779,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerPixel, this.bytesPerSample, pngMetaData.HasTrans, - pngMetaData.Rgb48Trans.GetValueOrDefault(), - pngMetaData.Rgb24Trans.GetValueOrDefault()); + pngMetaData.TransparentRgb48.GetValueOrDefault(), + pngMetaData.TransparentRgb24.GetValueOrDefault()); break; @@ -817,7 +817,7 @@ namespace SixLabors.ImageSharp.Formats.Png ushort gc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(2, 2)); ushort bc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(4, 2)); - pngMetaData.Rgb48Trans = new Rgb48(rc, gc, bc); + pngMetaData.TransparentRgb48 = new Rgb48(rc, gc, bc); pngMetaData.HasTrans = true; return; } @@ -825,7 +825,7 @@ namespace SixLabors.ImageSharp.Formats.Png byte r = ReadByteLittleEndian(alpha, 0); byte g = ReadByteLittleEndian(alpha, 2); byte b = ReadByteLittleEndian(alpha, 4); - pngMetaData.Rgb24Trans = new Rgb24(r, g, b); + pngMetaData.TransparentRgb24 = new Rgb24(r, g, b); pngMetaData.HasTrans = true; } } @@ -835,11 +835,11 @@ namespace SixLabors.ImageSharp.Formats.Png { if (this.header.BitDepth == 16) { - pngMetaData.Luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); + pngMetaData.TransparentGray16 = new Gray16(BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2))); } else { - pngMetaData.LuminanceTrans = ReadByteLittleEndian(alpha, 0); + pngMetaData.TransparentGray8 = new Gray8(ReadByteLittleEndian(alpha, 0)); } pngMetaData.HasTrans = true; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 1179a6db31..e953bc1f07 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -314,37 +314,37 @@ namespace SixLabors.ImageSharp.Formats.Png { if (pngMetaData.ColorType == PngColorType.Rgb) { - if (pngMetaData.Rgb48Trans != null) + if (pngMetaData.TransparentRgb48 != null) { - var r = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); - var g = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.R); - var b = BitConverter.GetBytes(pngMetaData.Rgb48Trans.Value.B); + var r = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R); + var g = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R); + var b = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.B); var alphaArray = r.Concat(g).Concat(b).ToArray(); this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } - else if (pngMetaData.Rgb24Trans != null) + else if (pngMetaData.TransparentRgb24 != null) { var alphaArray = new byte[6]; - alphaArray[1] = pngMetaData.Rgb24Trans.Value.R; - alphaArray[3] = pngMetaData.Rgb24Trans.Value.G; - alphaArray[5] = pngMetaData.Rgb24Trans.Value.B; + alphaArray[1] = pngMetaData.TransparentRgb24.Value.R; + alphaArray[3] = pngMetaData.TransparentRgb24.Value.G; + alphaArray[5] = pngMetaData.TransparentRgb24.Value.B; this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } } else if (pngMetaData.ColorType == PngColorType.Grayscale) { - if (pngMetaData.Luminance16Trans != null) + if (pngMetaData.TransparentGray16 != null) { - var alphaArray = BitConverter.GetBytes(pngMetaData.Luminance16Trans.Value); + var alphaArray = BitConverter.GetBytes(pngMetaData.TransparentGray16.Value.PackedValue); this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } - else if (pngMetaData.LuminanceTrans != null) + else if (pngMetaData.TransparentGray8 != null) { var alphaArray = new byte[2]; - alphaArray[1] = pngMetaData.LuminanceTrans.Value; + alphaArray[1] = pngMetaData.TransparentGray8.Value.PackedValue; this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); } diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 765222795a..6a293f770c 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -47,22 +47,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets or sets the Rgb 24 transparent color. This represents any color in an 8 bit Rgb24 encoded png that should be transparent /// - public Rgb24? Rgb24Trans { get; set; } + public Rgb24? TransparentRgb24 { get; set; } /// /// Gets or sets the Rgb 48 transparent color. This represents any color in a 16 bit Rgb24 encoded png that should be transparent /// - public Rgb48? Rgb48Trans { get; set; } + public Rgb48? TransparentRgb48 { get; set; } /// /// Gets or sets the 8 bit grayscale transparent color. This represents any color in an 8 bit grayscale encoded png that should be transparent /// - public byte? LuminanceTrans { get; set; } + public Gray8? TransparentGray8 { get; set; } /// /// Gets or sets the 16 bit grayscale transparent color. This represents any color in a 16 bit grayscale encoded png that should be transparent /// - public ushort? Luminance16Trans { get; set; } + public Gray16? TransparentGray16 { get; set; } /// /// Gets or sets a value indicating whether the image has transparency chunk and markers were decoded diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 3fe590ee24..528c012c58 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -20,8 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan scanlineSpan, Span rowSpan, bool hasTrans, - ushort luminance16Trans, - byte luminanceTrans) + Gray16 luminance16Trans, + Gray8 luminanceTrans) where TPixel : struct, IPixel { TPixel pixel = default; @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.R = luminance; rgba64.G = luminance; rgba64.B = luminance; - rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; + rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue; pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor); + byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); Rgba32 rgba32 = default; for (int x = 0; x < header.Width; x++) { @@ -93,8 +93,8 @@ namespace SixLabors.ImageSharp.Formats.Png int pixelOffset, int increment, bool hasTrans, - ushort luminance16Trans, - byte luminanceTrans) + Gray16 luminance16Trans, + Gray8 luminanceTrans) where TPixel : struct, IPixel { TPixel pixel = default; @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.R = luminance; rgba64.G = luminance; rgba64.B = luminance; - rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; + rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue; pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor); + byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); Rgba32 rgba32 = default; for (int x = pixelOffset; x < header.Width; x += increment) { From 5162e6b68c087a0553ee559eaa8b213c26e39402 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Fri, 2 Nov 2018 17:08:20 -0500 Subject: [PATCH 132/238] ImageSharp-762: Added methods to pre-seed AoT compiler on iOS --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 19 +++++++++++++++++++ .../OctreeFrameQuantizer{TPixel}.cs | 2 ++ 2 files changed, 21 insertions(+) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 8ddd4247e1..b226201082 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -5,6 +5,7 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp { @@ -35,5 +36,23 @@ namespace SixLabors.ImageSharp public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); + + /// + /// This method doesn't actually do anything but serves an important purpose... + /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: + /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." + /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT + /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on + /// iOS so it bombs out. + /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the + /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! + /// + /// The pixel format. + public static void AotCompileOctreeQuantizer() + where TPixel : struct, IPixel + { + var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); + test.AotGetPalette(); + } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 1eeb0be410..8f688e8387 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -136,6 +136,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + internal TPixel[] AotGetPalette() => this.octree.Palletize(this.colors); + /// protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors); From 265f27913c5134cd2de0ad015ca484183254474e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 00:19:09 +0100 Subject: [PATCH 133/238] benchmarks for current state --- .../Common/Helpers/InliningOptions.cs | 2 +- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 2 +- .../Codecs/Jpeg/DecodeJpeg.cs | 9 ++++ .../General/Block8x8F_LoadFromInt16.cs | 48 +++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index f61e4f8aef..ad85c4fc81 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. // Uncomment this for verbose profiler results: -#define PROFILING +// #define PROFILING using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 463961d868..9aeb209319 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp /// /// Widen and convert a vector of values into 2 vectors of -s. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void ConvertToSingle( Vector source, out Vector dest1, diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs index 2afacb1e4f..57dcede88d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs @@ -76,5 +76,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg // | | | | | | | | | | // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | + + // RESULTS (2018 November 1): + // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| + // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.59 ms | 4.611 ms | 0.2605 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | + // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 55.33 ms | 2.133 ms | 0.1205 ms | 3.15 | 0.04 | 125.0000 | 566.01 KB | + // | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.83 ms | 24.326 ms | 1.3745 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 44.93 ms | 3.088 ms | 0.1745 ms | 2.53 | 0.15 | 125.0000 | 529.96 KB | } } diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs b/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs new file mode 100644 index 0000000000..34847148bf --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs @@ -0,0 +1,48 @@ +using System; +using System.Numerics; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg.Components; + +namespace SixLabors.ImageSharp.Benchmarks.General +{ + public class Block8x8F_LoadFromInt16 + { + private Block8x8 source; + + private Block8x8F dest = default; + + [GlobalSetup] + public void Setup() + { + if (Vector.Count != 8) + { + throw new NotSupportedException("Vector.Count != 8"); + } + + for (short i = 0; i < Block8x8F.Size; i++) + { + this.source[i] = i; + } + } + + [Benchmark(Baseline = true)] + public void Scalar() + { + this.dest.LoadFromInt16Scalar(ref this.source); + } + + [Benchmark] + public void ExtendedAvx2() + { + this.dest.LoadFromInt16ExtendedAvx2(ref this.source); + } + + // RESULT: + // Method | Mean | Error | StdDev | Scaled | + // ------------- |---------:|----------:|----------:|-------:| + // Scalar | 34.88 ns | 0.3296 ns | 0.3083 ns | 1.00 | + // ExtendedAvx2 | 21.58 ns | 0.2125 ns | 0.1884 ns | 0.62 | + } +} \ No newline at end of file From 941e51cd16a613023a270854763f7b3770a9424f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 17:52:55 +0100 Subject: [PATCH 134/238] reimplement Block8x8F.CopyTo2x2 --- .../Jpeg/Components/Block8x8F.CopyTo.cs | 166 +++++----- .../BlockOperations/Block8x8F_CopyTo2x2.cs | 287 ++++++++++++++++++ .../BlockOperations}/Block8x8F_DivideRound.cs | 6 +- .../Block8x8F_LoadFromInt16.cs | 9 +- .../Jpeg/BlockOperations}/Block8x8F_Round.cs | 7 +- .../Jpg/Block8x8FTests.CopyToBufferArea.cs | 21 +- 6 files changed, 390 insertions(+), 106 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs rename tests/ImageSharp.Benchmarks/{General => Codecs/Jpeg/BlockOperations}/Block8x8F_DivideRound.cs (96%) rename tests/ImageSharp.Benchmarks/{General => Codecs/Jpeg/BlockOperations}/Block8x8F_LoadFromInt16.cs (83%) rename tests/ImageSharp.Benchmarks/{General => Codecs/Jpeg/BlockOperations}/Block8x8F_Round.cs (90%) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs index b7dd125a88..50f8b61212 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs @@ -12,55 +12,32 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components internal partial struct Block8x8F { /// - /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical. + /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical scale factors. /// + [MethodImpl(InliningOptions.ShortMethod)] public void CopyTo(in BufferArea area, int horizontalScale, int verticalScale) { if (horizontalScale == 1 && verticalScale == 1) { - this.CopyTo(area); + this.Copy1x1Scale(area); return; } - else if (horizontalScale == 2 && verticalScale == 2) + + if (horizontalScale == 2 && verticalScale == 2) { - this.CopyTo2x2(area); + this.Copy2x2Scale(area); return; } - ref float destBase = ref area.GetReferenceToOrigin(); - - // TODO: Optimize: implement all the cases with loopless special code! (T4?) - for (int y = 0; y < 8; y++) - { - int yy = y * verticalScale; - int y8 = y * 8; - - for (int x = 0; x < 8; x++) - { - int xx = x * horizontalScale; - - float value = this[y8 + x]; - - for (int i = 0; i < verticalScale; i++) - { - int baseIdx = ((yy + i) * area.Stride) + xx; - - for (int j = 0; j < horizontalScale; j++) - { - // area[xx + j, yy + i] = value; - Unsafe.Add(ref destBase, baseIdx + j) = value; - } - } - } - } + // TODO: Optimize: implement all the cases with scale-specific, loopless code! + this.CopyArbitraryScale(area, horizontalScale, verticalScale); } - // [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(in BufferArea area) + public void Copy1x1Scale(in BufferArea destination) { ref byte selfBase = ref Unsafe.As(ref this); - ref byte destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); - int destStride = area.Stride * sizeof(float); + ref byte destBase = ref Unsafe.As(ref destination.GetReferenceToOrigin()); + int destStride = destination.Stride * sizeof(float); CopyRowImpl(ref selfBase, ref destBase, destStride, 0); CopyRowImpl(ref selfBase, ref destBase, destStride, 1); @@ -80,10 +57,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float)); } - private void CopyTo2x2(in BufferArea area) + private void Copy2x2Scale(in BufferArea area) { - ref float destBase = ref area.GetReferenceToOrigin(); - int destStride = area.Stride; + ref Vector2 destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); + int destStride = area.Stride / 2; this.WidenCopyImpl2x2(ref destBase, 0, destStride); this.WidenCopyImpl2x2(ref destBase, 1, destStride); @@ -96,60 +73,75 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WidenCopyImpl2x2(ref float destBase, int row, int destStride) + private void WidenCopyImpl2x2(ref Vector2 destBase, int row, int destStride) { - ref Vector4 selfLeft = ref Unsafe.Add(ref this.V0L, 2 * row); - ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); - ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride); - - Unsafe.Add(ref destLocalOrigo, 0) = selfLeft.X; - Unsafe.Add(ref destLocalOrigo, 1) = selfLeft.X; - Unsafe.Add(ref destLocalOrigo, 2) = selfLeft.Y; - Unsafe.Add(ref destLocalOrigo, 3) = selfLeft.Y; - Unsafe.Add(ref destLocalOrigo, 4) = selfLeft.Z; - Unsafe.Add(ref destLocalOrigo, 5) = selfLeft.Z; - Unsafe.Add(ref destLocalOrigo, 6) = selfLeft.W; - Unsafe.Add(ref destLocalOrigo, 7) = selfLeft.W; - - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 0) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 1) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 2) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 3) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 4) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 5) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 6) = selfRight.W; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 7) = selfRight.W; - - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 0) = selfLeft.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 1) = selfLeft.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 2) = selfLeft.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 3) = selfLeft.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 4) = selfLeft.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 5) = selfLeft.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 6) = selfLeft.W; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 7) = selfLeft.W; - - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 0) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 1) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 2) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 3) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 4) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 5) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 6) = selfRight.W; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 7) = selfRight.W; + ref Vector4 sLeft = ref Unsafe.Add(ref this.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); + + var xLeft = new Vector4(sLeft.X); + var yLeft = new Vector4(sLeft.Y); + var zLeft = new Vector4(sLeft.Z); + var wLeft = new Vector4(sLeft.W); + + var xRight = new Vector4(sRight.X); + var yRight = new Vector4(sRight.Y); + var zRight = new Vector4(sRight.Z); + var wRight = new Vector4(sRight.W); + + Unsafe.As(ref dTopLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + + Unsafe.As(ref dTopRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; + + Unsafe.As(ref dBottomLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; + + Unsafe.As(ref dBottomRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WidenCopyImpl(ref Vector4 s, ref float destBase) + [MethodImpl(InliningOptions.ColdPath)] + private void CopyArbitraryScale(BufferArea area, int horizontalScale, int verticalScale) { - Unsafe.Add(ref destBase, 0) = s.X; - Unsafe.Add(ref destBase, 1) = s.X; - Unsafe.Add(ref destBase, 2) = s.Y; - Unsafe.Add(ref destBase, 3) = s.Y; - Unsafe.Add(ref destBase, 4) = s.Z; - Unsafe.Add(ref destBase, 5) = s.Z; - Unsafe.Add(ref destBase, 6) = s.W; - Unsafe.Add(ref destBase, 7) = s.W; + ref float destBase = ref area.GetReferenceToOrigin(); + + for (int y = 0; y < 8; y++) + { + int yy = y * verticalScale; + int y8 = y * 8; + + for (int x = 0; x < 8; x++) + { + int xx = x * horizontalScale; + + float value = this[y8 + x]; + + for (int i = 0; i < verticalScale; i++) + { + int baseIdx = ((yy + i) * area.Stride) + xx; + + for (int j = 0; j < horizontalScale; j++) + { + // area[xx + j, yy + i] = value; + Unsafe.Add(ref destBase, baseIdx + j) = value; + } + } + } + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs new file mode 100644 index 0000000000..89de95ee94 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -0,0 +1,287 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Memory; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations +{ + public class Block8x8F_CopyTo2x2 + { + private Block8x8F block; + + private Buffer2D buffer; + + private BufferArea destArea; + + [GlobalSetup] + public void Setup() + { + this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); + this.destArea = this.buffer.GetArea(200, 100, 128, 128); + } + + [Benchmark(Baseline = true)] + public void Original() + { + ref float destBase = ref this.destArea.GetReferenceToOrigin(); + int destStride = this.destArea.Stride; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2(ref Block8x8F src, ref float destBase, int row, int destStride) + { + ref Vector4 selfRight = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); + ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride); + + Unsafe.Add(ref destLocalOrigo, 0) = selfLeft.X; + Unsafe.Add(ref destLocalOrigo, 1) = selfLeft.X; + Unsafe.Add(ref destLocalOrigo, 2) = selfLeft.Y; + Unsafe.Add(ref destLocalOrigo, 3) = selfLeft.Y; + Unsafe.Add(ref destLocalOrigo, 4) = selfLeft.Z; + Unsafe.Add(ref destLocalOrigo, 5) = selfLeft.Z; + Unsafe.Add(ref destLocalOrigo, 6) = selfLeft.W; + Unsafe.Add(ref destLocalOrigo, 7) = selfLeft.W; + + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 0) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 1) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 2) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 3) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 4) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 5) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 6) = selfRight.W; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 7) = selfRight.W; + + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 0) = selfLeft.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 1) = selfLeft.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 2) = selfLeft.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 3) = selfLeft.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 4) = selfLeft.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 5) = selfLeft.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 6) = selfLeft.W; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 7) = selfLeft.W; + + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 0) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 1) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 2) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 3) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 4) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 5) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 6) = selfRight.W; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 7) = selfRight.W; + } + + [Benchmark] + public void Original_V2() + { + ref float destBase = ref this.destArea.GetReferenceToOrigin(); + int destStride = this.destArea.Stride; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_V2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_V2(ref Block8x8F src, ref float destBase, int row, int destStride) + { + ref Vector4 selfLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); + ref float dest0 = ref Unsafe.Add(ref destBase, row * 2 * destStride); + + Unsafe.Add(ref dest0, 0) = selfLeft.X; + Unsafe.Add(ref dest0, 1) = selfLeft.X; + Unsafe.Add(ref dest0, 2) = selfLeft.Y; + Unsafe.Add(ref dest0, 3) = selfLeft.Y; + Unsafe.Add(ref dest0, 4) = selfLeft.Z; + Unsafe.Add(ref dest0, 5) = selfLeft.Z; + Unsafe.Add(ref dest0, 6) = selfLeft.W; + Unsafe.Add(ref dest0, 7) = selfLeft.W; + + ref float dest1 = ref Unsafe.Add(ref dest0, 8); + + Unsafe.Add(ref dest1, 0) = selfRight.X; + Unsafe.Add(ref dest1, 1) = selfRight.X; + Unsafe.Add(ref dest1, 2) = selfRight.Y; + Unsafe.Add(ref dest1, 3) = selfRight.Y; + Unsafe.Add(ref dest1, 4) = selfRight.Z; + Unsafe.Add(ref dest1, 5) = selfRight.Z; + Unsafe.Add(ref dest1, 6) = selfRight.W; + Unsafe.Add(ref dest1, 7) = selfRight.W; + + ref float dest2 = ref Unsafe.Add(ref dest0, destStride); + + Unsafe.Add(ref dest2, 0) = selfLeft.X; + Unsafe.Add(ref dest2, 1) = selfLeft.X; + Unsafe.Add(ref dest2, 2) = selfLeft.Y; + Unsafe.Add(ref dest2, 3) = selfLeft.Y; + Unsafe.Add(ref dest2, 4) = selfLeft.Z; + Unsafe.Add(ref dest2, 5) = selfLeft.Z; + Unsafe.Add(ref dest2, 6) = selfLeft.W; + Unsafe.Add(ref dest2, 7) = selfLeft.W; + + ref float dest3 = ref Unsafe.Add(ref dest2, 8); + + Unsafe.Add(ref dest3, 0) = selfRight.X; + Unsafe.Add(ref dest3, 1) = selfRight.X; + Unsafe.Add(ref dest3, 2) = selfRight.Y; + Unsafe.Add(ref dest3, 3) = selfRight.Y; + Unsafe.Add(ref dest3, 4) = selfRight.Z; + Unsafe.Add(ref dest3, 5) = selfRight.Z; + Unsafe.Add(ref dest3, 6) = selfRight.W; + Unsafe.Add(ref dest3, 7) = selfRight.W; + } + + [Benchmark] + public void UseVector2() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector2(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); + + var xLeft = new Vector2(sLeft.X); + var yLeft = new Vector2(sLeft.Y); + var zLeft = new Vector2(sLeft.Z); + var wLeft = new Vector2(sLeft.W); + + var xRight = new Vector2(sRight.X); + var yRight = new Vector2(sRight.Y); + var zRight = new Vector2(sRight.Z); + var wRight = new Vector2(sRight.W); + + dTopLeft = xLeft; + Unsafe.Add(ref dTopLeft, 1) = yLeft; + Unsafe.Add(ref dTopLeft, 2) = zLeft; + Unsafe.Add(ref dTopLeft, 3) = wLeft; + + dTopRight = xRight; + Unsafe.Add(ref dTopRight, 1) = yRight; + Unsafe.Add(ref dTopRight, 2) = zRight; + Unsafe.Add(ref dTopRight, 3) = wRight; + + dBottomLeft = xLeft; + Unsafe.Add(ref dBottomLeft, 1) = yLeft; + Unsafe.Add(ref dBottomLeft, 2) = zLeft; + Unsafe.Add(ref dBottomLeft, 3) = wLeft; + + dBottomRight = xRight; + Unsafe.Add(ref dBottomRight, 1) = yRight; + Unsafe.Add(ref dBottomRight, 2) = zRight; + Unsafe.Add(ref dBottomRight, 3) = wRight; + } + + [Benchmark] + public void UseVector4() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector4(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); + + var xLeft = new Vector4(sLeft.X); + var yLeft = new Vector4(sLeft.Y); + var zLeft = new Vector4(sLeft.Z); + var wLeft = new Vector4(sLeft.W); + + var xRight = new Vector4(sRight.X); + var yRight = new Vector4(sRight.Y); + var zRight = new Vector4(sRight.Z); + var wRight = new Vector4(sRight.W); + + Unsafe.As(ref dTopLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + + Unsafe.As(ref dTopRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; + + Unsafe.As(ref dBottomLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; + + Unsafe.As(ref dBottomRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; + } + + // RESULTS: + // Method | Mean | Error | StdDev | Scaled | + // ------------ |---------:|----------:|----------:|-------:| + // Original | 88.93 ns | 0.7783 ns | 0.6899 ns | 1.00 | + // Original_V2 | 88.39 ns | 0.9426 ns | 0.8356 ns | 0.99 | + // UseVector2 | 45.63 ns | 0.4248 ns | 0.3548 ns | 0.51 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs similarity index 96% rename from tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs index fcc5f9a592..5502475d43 100644 --- a/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs @@ -10,7 +10,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { /// /// The goal of this benchmark is to measure the following Jpeg-related scenario: @@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Benchmarks.General private static readonly Vector4 MinusOne = new Vector4(-1); private static readonly Vector4 Half = new Vector4(0.5f); - private Block8x8F inputDividend = default(Block8x8F); - private Block8x8F inputDivisior = default(Block8x8F); + private Block8x8F inputDividend; + private Block8x8F inputDivisior; [GlobalSetup] public void Setup() diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs similarity index 83% rename from tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs index 34847148bf..29ee402a00 100644 --- a/tests/ImageSharp.Benchmarks/General/Block8x8F_LoadFromInt16.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs @@ -1,11 +1,16 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming + +using System; using System.Numerics; using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { public class Block8x8F_LoadFromInt16 { diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs similarity index 90% rename from tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs index 200af64c25..c7b5802c4f 100644 --- a/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs @@ -1,4 +1,7 @@ -// ReSharper disable InconsistentNaming +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming using System; using System.Numerics; @@ -8,7 +11,7 @@ using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { public class Block8x8F_Round { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index c720fdd4a7..3f426e232d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -11,10 +11,11 @@ using SixLabors.Primitives; using Xunit; using Xunit.Abstractions; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Jpg { - public partial class Block8x8FTests : JpegFixture + public partial class Block8x8FTests { public class CopyToBufferArea : JpegFixture { @@ -37,17 +38,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } - // TODO: This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative. - [Fact(Skip = "This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative.")] - //[Fact] - public void Unscaled() + [Fact] + public void Copy1x1Scale() { Block8x8F block = CreateRandomFloatBlock(0, 100); - using (var buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20)) { BufferArea area = buffer.GetArea(5, 10, 8, 8); - block.CopyTo(area); + block.Copy1x1Scale(area); Assert.Equal(block[0, 0], buffer[5, 10]); Assert.Equal(block[1, 0], buffer[6, 10]); @@ -59,22 +58,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } - // TODO: This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative. - [Theory(Skip = "This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative.")] - //[Theory] + [Theory] [InlineData(1, 1)] [InlineData(1, 2)] [InlineData(2, 1)] [InlineData(2, 2)] [InlineData(4, 2)] [InlineData(4, 4)] - public void Scaled(int horizontalFactor, int verticalFactor) + public void CopyTo(int horizontalFactor, int verticalFactor) { Block8x8F block = CreateRandomFloatBlock(0, 100); var start = new Point(50, 50); - using (var buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100)) { BufferArea area = buffer.GetArea(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); block.CopyTo(area, horizontalFactor, verticalFactor); From bc79b188176cb9db206006b21993a98b1fb99e2c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 18:31:43 +0100 Subject: [PATCH 135/238] Optimization: do not initialize pixel buffer in JpegDecoder --- .../Formats/Jpeg/JpegDecoderCore.cs | 10 ++++++-- src/ImageSharp/Image.Decode.cs | 24 ++++++++++++++++++ tests/ImageSharp.Tests/Image/ImageTests.cs | 25 ++++++++++++++++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 68252f624c..ef73aab38f 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -936,12 +936,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private Image PostProcessIntoImage() where TPixel : struct, IPixel { + var image = Image.CreateUninitialized( + this.configuration, + this.ImageWidth, + this.ImageHeight, + this.MetaData); + using (var postProcessor = new JpegImagePostProcessor(this.configuration, this)) { - var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); postProcessor.PostProcess(image.Frames.RootFrame); - return image; } + + return image; } } } \ No newline at end of file diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 8b9f3fdb5b..ffdab25e24 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; @@ -15,6 +16,29 @@ namespace SixLabors.ImageSharp /// public static partial class Image { + /// + /// Creates an instance backed by an uninitialized memory buffer. + /// This is an optimized creation method intended to be used by decoders. + /// The image might be filled with memory garbage. + /// + /// The pixel type + /// The + /// The width of the image + /// The height of the image + /// The + /// The result + internal static Image CreateUninitialized( + Configuration configuration, + int width, + int height, + ImageMetaData metadata) + where TPixel : struct, IPixel + { + Buffer2D uninitializedMemoryBuffer = + configuration.MemoryAllocator.Allocate2D(width, height); + return new Image(configuration, uninitializedMemoryBuffer.MemorySource, width, height, metadata); + } + /// /// By reading the header on the provided stream this calculates the images format. /// diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index f3c04d5e14..c5c7d19e1e 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -2,7 +2,10 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.Memory; + using Xunit; // ReSharper disable InconsistentNaming @@ -46,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests } [Fact] - public void Configuration_Width_Height_BackroundColor() + public void Configuration_Width_Height_BackgroundColor() { Configuration configuration = Configuration.Default.Clone(); Rgba32 color = Rgba32.Aquamarine; @@ -61,6 +64,26 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(configuration, image.GetConfiguration()); } } + + [Fact] + public void CreateUninitialized() + { + Configuration configuration = Configuration.Default.Clone(); + + byte dirtyValue = 123; + configuration.MemoryAllocator = new TestMemoryAllocator(dirtyValue); + var metadata = new ImageMetaData(); + + using (Image image = Image.CreateUninitialized(configuration, 21, 22, metadata)) + { + Assert.Equal(21, image.Width); + Assert.Equal(22, image.Height); + Assert.Same(configuration, image.GetConfiguration()); + Assert.Same(metadata, image.MetaData); + + Assert.Equal(dirtyValue, image[5, 5].PackedValue); + } + } } } } From c1e4ccb1728c4deb75d46d52af11c1faddbb3b80 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 20:43:50 +0100 Subject: [PATCH 136/238] improved Block8x8F.Copy2x2Scale --- .../Jpeg/Components/Block8x8F.CopyTo.cs | 42 +++---- .../BlockOperations/Block8x8F_CopyTo1x1.cs | 82 ++++++++++++++ .../BlockOperations/Block8x8F_CopyTo2x2.cs | 104 ++++++++++++++---- 3 files changed, 190 insertions(+), 38 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs index 50f8b61212..5fa3e91d75 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return; } - // TODO: Optimize: implement all the cases with scale-specific, loopless code! + // TODO: Optimize: implement all cases with scale-specific, loopless code! this.CopyArbitraryScale(area, horizontalScale, verticalScale); } @@ -79,9 +79,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); - ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); - ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); var xLeft = new Vector4(sLeft.X); var yLeft = new Vector4(sLeft.Y); @@ -91,27 +89,33 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components var xRight = new Vector4(sRight.X); var yRight = new Vector4(sRight.Y); var zRight = new Vector4(sRight.Z); - var wRight = new Vector4(sRight.W); + var wRight = new Vector2(sRight.W); Unsafe.As(ref dTopLeft) = xLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + AssignVector4Value(ref dTopLeft, 1, ref yLeft); + AssignVector4Value(ref dTopLeft, 2, ref zLeft); + AssignVector4Value(ref dTopLeft, 3, ref wLeft); - Unsafe.As(ref dTopRight) = xRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; + AssignVector4Value(ref dTopLeft, 4, ref xRight); + AssignVector4Value(ref dTopLeft, 5, ref yRight); + AssignVector4Value(ref dTopLeft, 6, ref zRight); + Unsafe.Add(ref dTopLeft, 7) = wRight; Unsafe.As(ref dBottomLeft) = xLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; - - Unsafe.As(ref dBottomRight) = xRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; + AssignVector4Value(ref dBottomLeft, 1, ref yLeft); + AssignVector4Value(ref dBottomLeft, 2, ref zLeft); + AssignVector4Value(ref dBottomLeft, 3, ref wLeft); + + AssignVector4Value(ref dBottomLeft, 4, ref xRight); + AssignVector4Value(ref dBottomLeft, 5, ref yRight); + AssignVector4Value(ref dBottomLeft, 6, ref zRight); + Unsafe.Add(ref dBottomLeft, 7) = wRight; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value) + { + Unsafe.As(ref Unsafe.Add(ref destBase, offset)) = value; } [MethodImpl(InliningOptions.ColdPath)] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs new file mode 100644 index 0000000000..96eecc456a --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs @@ -0,0 +1,82 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations +{ + public class Block8x8F_CopyTo1x1 + { + private Block8x8F block; + + private Buffer2D buffer; + + private BufferArea destArea; + + [GlobalSetup] + public void Setup() + { + if (!SimdUtils.IsAvx2CompatibleArchitecture) + { + throw new InvalidOperationException("Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support."); + } + + this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); + this.destArea = this.buffer.GetArea(200, 100, 64, 64); + } + + [Benchmark(Baseline = true)] + public void Original() + { + ref byte selfBase = ref Unsafe.As(ref this.block); + ref byte destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride * sizeof(float); + + CopyRowImpl(ref selfBase, ref destBase, destStride, 0); + CopyRowImpl(ref selfBase, ref destBase, destStride, 1); + CopyRowImpl(ref selfBase, ref destBase, destStride, 2); + CopyRowImpl(ref selfBase, ref destBase, destStride, 3); + CopyRowImpl(ref selfBase, ref destBase, destStride, 4); + CopyRowImpl(ref selfBase, ref destBase, destStride, 5); + CopyRowImpl(ref selfBase, ref destBase, destStride, 6); + CopyRowImpl(ref selfBase, ref destBase, destStride, 7); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void CopyRowImpl(ref byte selfBase, ref byte destBase, int destStride, int row) + { + ref byte s = ref Unsafe.Add(ref selfBase, row * 8 * sizeof(float)); + ref byte d = ref Unsafe.Add(ref destBase, row * destStride); + Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float)); + } + + [Benchmark] + public void UseVector8() + { + ref Block8x8F s = ref this.block; + ref Vector d = ref Unsafe.As>(ref this.destArea.GetReferenceToOrigin()); + + Vector row0 = Unsafe.As>(ref s.V0L); + Vector row1 = Unsafe.As>(ref s.V1L); + Vector row2 = Unsafe.As>(ref s.V2L); + Vector row3 = Unsafe.As>(ref s.V3L); + Vector row4 = Unsafe.As>(ref s.V4L); + Vector row5 = Unsafe.As>(ref s.V5L); + Vector row6 = Unsafe.As>(ref s.V6L); + Vector row7 = Unsafe.As>(ref s.V7L); + + d = row0; + Unsafe.Add(ref d, 1) = row1; + Unsafe.Add(ref d, 2) = row2; + Unsafe.Add(ref d, 3) = row3; + Unsafe.Add(ref d, 4) = row4; + Unsafe.Add(ref d, 5) = row5; + Unsafe.Add(ref d, 6) = row6; + Unsafe.Add(ref d, 7) = row7; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs index 89de95ee94..269a3e0d81 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void WidenCopyImpl2x2(ref Block8x8F src, ref float destBase, int row, int destStride) { - ref Vector4 selfRight = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 selfLeft = ref Unsafe.Add(ref src.V0L, 2 * row); ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride); @@ -257,31 +257,97 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations var wRight = new Vector4(sRight.W); Unsafe.As(ref dTopLeft) = xLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; - Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; - + AssignVector4Value(ref dTopLeft, 1, ref yLeft); + AssignVector4Value(ref dTopLeft, 2, ref zLeft); + AssignVector4Value(ref dTopLeft, 3, ref wLeft); + Unsafe.As(ref dTopRight) = xRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; - Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; + AssignVector4Value(ref dTopRight, 1, ref yRight); + AssignVector4Value(ref dTopRight, 2, ref zRight); + AssignVector4Value(ref dTopRight, 3, ref wRight); Unsafe.As(ref dBottomLeft) = xLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; - Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; + AssignVector4Value(ref dBottomLeft, 1, ref yLeft); + AssignVector4Value(ref dBottomLeft, 2, ref zLeft); + AssignVector4Value(ref dBottomLeft, 3, ref wLeft); Unsafe.As(ref dBottomRight) = xRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; - Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; + AssignVector4Value(ref dBottomRight, 1, ref yRight); + AssignVector4Value(ref dBottomRight, 2, ref zRight); + AssignVector4Value(ref dBottomRight, 3, ref wRight); + } + + [Benchmark] + public void UseVector4_SafeRightCorner() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector4_SafeRightCorner(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + + var xLeft = new Vector4(sLeft.X); + var yLeft = new Vector4(sLeft.Y); + var zLeft = new Vector4(sLeft.Z); + var wLeft = new Vector4(sLeft.W); + + var xRight = new Vector4(sRight.X); + var yRight = new Vector4(sRight.Y); + var zRight = new Vector4(sRight.Z); + var wRight = new Vector2(sRight.W); + + Unsafe.As(ref dTopLeft) = xLeft; + AssignVector4Value(ref dTopLeft, 1, ref yLeft); + AssignVector4Value(ref dTopLeft, 2, ref zLeft); + AssignVector4Value(ref dTopLeft, 3, ref wLeft); + + AssignVector4Value(ref dTopLeft, 4, ref xRight); + AssignVector4Value(ref dTopLeft, 5, ref yRight); + AssignVector4Value(ref dTopLeft, 6, ref zRight); + Unsafe.Add(ref dTopLeft, 7) = wRight; + + Unsafe.As(ref dBottomLeft) = xLeft; + AssignVector4Value(ref dBottomLeft, 1, ref yLeft); + AssignVector4Value(ref dBottomLeft, 2, ref zLeft); + AssignVector4Value(ref dBottomLeft, 3, ref wLeft); + + AssignVector4Value(ref dBottomLeft, 4, ref xRight); + AssignVector4Value(ref dBottomLeft, 5, ref yRight); + AssignVector4Value(ref dBottomLeft, 6, ref zRight); + Unsafe.Add(ref dBottomLeft, 7) = wRight; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value) + { + Unsafe.As(ref Unsafe.Add(ref destBase, offset)) = value; } // RESULTS: - // Method | Mean | Error | StdDev | Scaled | - // ------------ |---------:|----------:|----------:|-------:| - // Original | 88.93 ns | 0.7783 ns | 0.6899 ns | 1.00 | - // Original_V2 | 88.39 ns | 0.9426 ns | 0.8356 ns | 0.99 | - // UseVector2 | 45.63 ns | 0.4248 ns | 0.3548 ns | 0.51 | + // Method | Mean | Error | StdDev | Scaled | ScaledSD | + // --------------------------- |---------:|----------:|----------:|-------:|---------:| + // Original | 93.78 ns | 1.8419 ns | 1.9708 ns | 1.00 | 0.00 | + // Original_V2 | 89.85 ns | 0.8809 ns | 0.7356 ns | 0.96 | 0.02 | + // UseVector2 | 81.81 ns | 0.4441 ns | 0.3937 ns | 0.87 | 0.02 | + // UseVector4 | 55.74 ns | 0.3674 ns | 0.3068 ns | 0.59 | 0.01 | + // UseVector4_SafeRightCorner | 55.70 ns | 0.3239 ns | 0.2705 ns | 0.59 | 0.01 | } } \ No newline at end of file From c34e4ff85fa0f23cad7546182d02b8308e2f3bd4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 21:30:36 +0100 Subject: [PATCH 137/238] optimize ExifReader.ToEnum(...) --- .../MetaData/Profiles/Exif/ExifReader.cs | 21 +++++- .../BlockOperations/Block8x8F_CopyTo1x1.cs | 73 ++++++++++++++++--- .../Jpg/Block8x8FTests.CopyToBufferArea.cs | 3 +- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 5 +- 4 files changed, 84 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 3326c3217a..c6a5b7d232 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private byte ConvertToByte(ReadOnlySpan buffer) => buffer[0]; - private unsafe string ConvertToString(ReadOnlySpan buffer) + private string ConvertToString(ReadOnlySpan buffer) { int nullCharIndex = buffer.IndexOf((byte)0); @@ -382,13 +382,13 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.invalidTags.Add(tag); } + [MethodImpl(InliningOptions.ShortMethod)] private TEnum ToEnum(int value, TEnum defaultValue) where TEnum : struct { - var enumValue = (TEnum)(object)value; - if (Enum.GetValues(typeof(TEnum)).Cast().Any(v => v.Equals(enumValue))) + if (EnumHelper.IsDefined(value)) { - return enumValue; + return Unsafe.As(ref value); } return defaultValue; @@ -557,5 +557,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif ? BinaryPrimitives.ReadInt16BigEndian(buffer) : BinaryPrimitives.ReadInt16LittleEndian(buffer); } + + private class EnumHelper + where TEnum : struct + { + private static readonly int[] Values = Enum.GetValues(typeof(TEnum)).Cast() + .Select(e => Convert.ToInt32(e)).OrderBy(e => e).ToArray(); + + [MethodImpl(InliningOptions.ShortMethod)] + public static bool IsDefined(int value) + { + return Array.BinarySearch(Values, 0, Values.Length, value) > 0; + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs index 96eecc456a..bf9b1af338 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -6,6 +9,7 @@ using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Memory; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { @@ -22,7 +26,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { if (!SimdUtils.IsAvx2CompatibleArchitecture) { - throw new InvalidOperationException("Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support."); + throw new InvalidOperationException("Benchmark Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support."); } this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); @@ -58,7 +62,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations public void UseVector8() { ref Block8x8F s = ref this.block; - ref Vector d = ref Unsafe.As>(ref this.destArea.GetReferenceToOrigin()); + ref float origin = ref this.destArea.GetReferenceToOrigin(); + int stride = this.destArea.Stride; + + ref Vector d0 = ref Unsafe.As>(ref origin); + ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride)); + ref Vector d2 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 2)); + ref Vector d3 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 3)); + ref Vector d4 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 4)); + ref Vector d5 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 5)); + ref Vector d6 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 6)); + ref Vector d7 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 7)); Vector row0 = Unsafe.As>(ref s.V0L); Vector row1 = Unsafe.As>(ref s.V1L); @@ -69,14 +83,51 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations Vector row6 = Unsafe.As>(ref s.V6L); Vector row7 = Unsafe.As>(ref s.V7L); - d = row0; - Unsafe.Add(ref d, 1) = row1; - Unsafe.Add(ref d, 2) = row2; - Unsafe.Add(ref d, 3) = row3; - Unsafe.Add(ref d, 4) = row4; - Unsafe.Add(ref d, 5) = row5; - Unsafe.Add(ref d, 6) = row6; - Unsafe.Add(ref d, 7) = row7; + d0 = row0; + d1 = row1; + d2 = row2; + d3 = row3; + d4 = row4; + d5 = row5; + d6 = row6; + d7 = row7; + } + + [Benchmark] + public void UseVector8_V2() + { + ref Block8x8F s = ref this.block; + ref float origin = ref this.destArea.GetReferenceToOrigin(); + int stride = this.destArea.Stride; + + ref Vector d0 = ref Unsafe.As>(ref origin); + ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride)); + ref Vector d2 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 2)); + ref Vector d3 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 3)); + ref Vector d4 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 4)); + ref Vector d5 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 5)); + ref Vector d6 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 6)); + ref Vector d7 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 7)); + + d0 = Unsafe.As>(ref s.V0L); + d1 = Unsafe.As>(ref s.V1L); + d2 = Unsafe.As>(ref s.V2L); + d3 = Unsafe.As>(ref s.V3L); + d4 = Unsafe.As>(ref s.V4L); + d5 = Unsafe.As>(ref s.V5L); + d6 = Unsafe.As>(ref s.V6L); + d7 = Unsafe.As>(ref s.V7L); } + + // RESULTS: + // + // Method | Mean | Error | StdDev | Scaled | + // -------------- |---------:|----------:|----------:|-------:| + // Original | 22.53 ns | 0.1660 ns | 0.1553 ns | 1.00 | + // UseVector8 | 21.59 ns | 0.3079 ns | 0.2571 ns | 0.96 | + // UseVector8_V2 | 22.57 ns | 0.1699 ns | 0.1506 ns | 1.00 | + // + // Conclusion: + // Doesn't worth to bother with this } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index 3f426e232d..d5eaaa2949 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; +using SixLabors.Memory; using SixLabors.Primitives; using Xunit; @@ -71,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var start = new Point(50, 50); - using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100, AllocationOptions.Clean)) { BufferArea area = buffer.GetArea(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); block.CopyTo(area, horizontalFactor, verticalFactor); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index 7d5130e1bc..88959bfabd 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -32,8 +32,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Jpeg444, }; - //[Theory] // Benchmark, enable manually - //[MemberData(nameof(DecodeJpegData))] + [Theory] // Benchmark, enable manually + [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); @@ -62,6 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg () => { var img = Image.Load(bytes, decoder); + img.Dispose(); }, // ReSharper disable once ExplicitCallerInfoArgument $"Decode {fileName}"); From b32694590da020985d443254a0305be21bb5f8a5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 22:05:06 +0100 Subject: [PATCH 138/238] Even better Copy2x2. Tests: Group together & refactor profiling benchmarks --- .../Jpeg/Components/Block8x8F.CopyTo.cs | 85 ++++++------- .../BlockOperations/Block8x8F_CopyTo2x2.cs | 115 +++++++++++++----- tests/ImageSharp.Sandbox46/Program.cs | 5 +- .../JpegBenchmarks.cs} | 23 ++-- .../LoadResizeSaveBenchmarks.cs} | 24 ++-- .../ProfilingBenchmarks/ProfilingSetup.cs | 18 +++ 6 files changed, 164 insertions(+), 106 deletions(-) rename tests/ImageSharp.Tests/{Formats/Jpg/JpegProfilingBenchmarks.cs => ProfilingBenchmarks/JpegBenchmarks.cs} (84%) rename tests/ImageSharp.Tests/{ProfilingBenchmarks.cs => ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs} (67%) create mode 100644 tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs index 5fa3e91d75..6bf9c8483a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs @@ -3,9 +3,9 @@ using System.Numerics; using System.Runtime.CompilerServices; - using SixLabors.ImageSharp.Memory; +// ReSharper disable UseObjectOrCollectionInitializer // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Formats.Jpeg.Components { @@ -62,60 +62,51 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components ref Vector2 destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); int destStride = area.Stride / 2; - this.WidenCopyImpl2x2(ref destBase, 0, destStride); - this.WidenCopyImpl2x2(ref destBase, 1, destStride); - this.WidenCopyImpl2x2(ref destBase, 2, destStride); - this.WidenCopyImpl2x2(ref destBase, 3, destStride); - this.WidenCopyImpl2x2(ref destBase, 4, destStride); - this.WidenCopyImpl2x2(ref destBase, 5, destStride); - this.WidenCopyImpl2x2(ref destBase, 6, destStride); - this.WidenCopyImpl2x2(ref destBase, 7, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 0, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 1, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 2, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 3, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 4, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 5, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 6, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 7, destStride); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WidenCopyImpl2x2(ref Vector2 destBase, int row, int destStride) + private void WidenCopyRowImpl2x2(ref Vector2 destBase, int row, int destStride) { ref Vector4 sLeft = ref Unsafe.Add(ref this.V0L, 2 * row); ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); - ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); - ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); - - var xLeft = new Vector4(sLeft.X); - var yLeft = new Vector4(sLeft.Y); - var zLeft = new Vector4(sLeft.Z); - var wLeft = new Vector4(sLeft.W); - - var xRight = new Vector4(sRight.X); - var yRight = new Vector4(sRight.Y); - var zRight = new Vector4(sRight.Z); - var wRight = new Vector2(sRight.W); - - Unsafe.As(ref dTopLeft) = xLeft; - AssignVector4Value(ref dTopLeft, 1, ref yLeft); - AssignVector4Value(ref dTopLeft, 2, ref zLeft); - AssignVector4Value(ref dTopLeft, 3, ref wLeft); - - AssignVector4Value(ref dTopLeft, 4, ref xRight); - AssignVector4Value(ref dTopLeft, 5, ref yRight); - AssignVector4Value(ref dTopLeft, 6, ref zRight); - Unsafe.Add(ref dTopLeft, 7) = wRight; - - Unsafe.As(ref dBottomLeft) = xLeft; - AssignVector4Value(ref dBottomLeft, 1, ref yLeft); - AssignVector4Value(ref dBottomLeft, 2, ref zLeft); - AssignVector4Value(ref dBottomLeft, 3, ref wLeft); - - AssignVector4Value(ref dBottomLeft, 4, ref xRight); - AssignVector4Value(ref dBottomLeft, 5, ref yRight); - AssignVector4Value(ref dBottomLeft, 6, ref zRight); - Unsafe.Add(ref dBottomLeft, 7) = wRight; - } + int offset = 2 * row * destStride; + ref Vector4 dTopLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset)); + ref Vector4 dBottomLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset + destStride)); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value) - { - Unsafe.As(ref Unsafe.Add(ref destBase, offset)) = value; + var xyLeft = new Vector4(sLeft.X); + xyLeft.Z = sLeft.Y; + xyLeft.W = sLeft.Y; + + var zwLeft = new Vector4(sLeft.Z); + zwLeft.Z = sLeft.W; + zwLeft.W = sLeft.W; + + var xyRight = new Vector4(sRight.X); + xyRight.Z = sRight.Y; + xyRight.W = sRight.Y; + + var zwRight = new Vector4(sRight.Z); + zwRight.Z = sRight.W; + zwRight.W = sRight.W; + + dTopLeft = xyLeft; + Unsafe.Add(ref dTopLeft, 1) = zwLeft; + Unsafe.Add(ref dTopLeft, 2) = xyRight; + Unsafe.Add(ref dTopLeft, 3) = zwRight; + + dBottomLeft = xyLeft; + Unsafe.Add(ref dBottomLeft, 1) = zwLeft; + Unsafe.Add(ref dBottomLeft, 2) = xyRight; + Unsafe.Add(ref dBottomLeft, 3) = zwRight; } [MethodImpl(InliningOptions.ColdPath)] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs index 269a3e0d81..65176af5bb 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -257,24 +257,24 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations var wRight = new Vector4(sRight.W); Unsafe.As(ref dTopLeft) = xLeft; - AssignVector4Value(ref dTopLeft, 1, ref yLeft); - AssignVector4Value(ref dTopLeft, 2, ref zLeft); - AssignVector4Value(ref dTopLeft, 3, ref wLeft); - + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + Unsafe.As(ref dTopRight) = xRight; - AssignVector4Value(ref dTopRight, 1, ref yRight); - AssignVector4Value(ref dTopRight, 2, ref zRight); - AssignVector4Value(ref dTopRight, 3, ref wRight); + Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; Unsafe.As(ref dBottomLeft) = xLeft; - AssignVector4Value(ref dBottomLeft, 1, ref yLeft); - AssignVector4Value(ref dBottomLeft, 2, ref zLeft); - AssignVector4Value(ref dBottomLeft, 3, ref wLeft); + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; Unsafe.As(ref dBottomRight) = xRight; - AssignVector4Value(ref dBottomRight, 1, ref yRight); - AssignVector4Value(ref dBottomRight, 2, ref zRight); - AssignVector4Value(ref dBottomRight, 3, ref wRight); + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; } [Benchmark] @@ -315,39 +315,90 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations var wRight = new Vector2(sRight.W); Unsafe.As(ref dTopLeft) = xLeft; - AssignVector4Value(ref dTopLeft, 1, ref yLeft); - AssignVector4Value(ref dTopLeft, 2, ref zLeft); - AssignVector4Value(ref dTopLeft, 3, ref wLeft); + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; - AssignVector4Value(ref dTopLeft, 4, ref xRight); - AssignVector4Value(ref dTopLeft, 5, ref yRight); - AssignVector4Value(ref dTopLeft, 6, ref zRight); + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 4)) = xRight; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 5)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 6)) = zRight; Unsafe.Add(ref dTopLeft, 7) = wRight; Unsafe.As(ref dBottomLeft) = xLeft; - AssignVector4Value(ref dBottomLeft, 1, ref yLeft); - AssignVector4Value(ref dBottomLeft, 2, ref zLeft); - AssignVector4Value(ref dBottomLeft, 3, ref wLeft); + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; - AssignVector4Value(ref dBottomLeft, 4, ref xRight); - AssignVector4Value(ref dBottomLeft, 5, ref yRight); - AssignVector4Value(ref dBottomLeft, 6, ref zRight); + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 4)) = xRight; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 5)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 6)) = zRight; Unsafe.Add(ref dBottomLeft, 7) = wRight; } + + [Benchmark] + public void UseVector4_V2() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 7, destStride); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value) + private static void WidenCopyImpl2x2_Vector4_V2(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) { - Unsafe.As(ref Unsafe.Add(ref destBase, offset)) = value; + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + int offset = 2 * row * destStride; + ref Vector4 dTopLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset)); + ref Vector4 dBottomLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset + destStride)); + + var xyLeft = new Vector4(sLeft.X); + xyLeft.Z = sLeft.Y; + xyLeft.W = sLeft.Y; + + var zwLeft = new Vector4(sLeft.Z); + zwLeft.Z = sLeft.W; + zwLeft.W = sLeft.W; + + var xyRight = new Vector4(sRight.X); + xyRight.Z = sRight.Y; + xyRight.W = sRight.Y; + + var zwRight = new Vector4(sRight.Z); + zwRight.Z = sRight.W; + zwRight.W = sRight.W; + + dTopLeft = xyLeft; + Unsafe.Add(ref dTopLeft, 1) = zwLeft; + Unsafe.Add(ref dTopLeft, 2) = xyRight; + Unsafe.Add(ref dTopLeft, 3) = zwRight; + + dBottomLeft = xyLeft; + Unsafe.Add(ref dBottomLeft, 1) = zwLeft; + Unsafe.Add(ref dBottomLeft, 2) = xyRight; + Unsafe.Add(ref dBottomLeft, 3) = zwRight; } // RESULTS: // Method | Mean | Error | StdDev | Scaled | ScaledSD | // --------------------------- |---------:|----------:|----------:|-------:|---------:| - // Original | 93.78 ns | 1.8419 ns | 1.9708 ns | 1.00 | 0.00 | - // Original_V2 | 89.85 ns | 0.8809 ns | 0.7356 ns | 0.96 | 0.02 | - // UseVector2 | 81.81 ns | 0.4441 ns | 0.3937 ns | 0.87 | 0.02 | - // UseVector4 | 55.74 ns | 0.3674 ns | 0.3068 ns | 0.59 | 0.01 | - // UseVector4_SafeRightCorner | 55.70 ns | 0.3239 ns | 0.2705 ns | 0.59 | 0.01 | + // Original | 92.69 ns | 2.4722 ns | 2.7479 ns | 1.00 | 0.00 | + // Original_V2 | 91.72 ns | 1.2089 ns | 1.0095 ns | 0.99 | 0.03 | + // UseVector2 | 86.70 ns | 0.5873 ns | 0.5206 ns | 0.94 | 0.03 | + // UseVector4 | 55.42 ns | 0.2482 ns | 0.2322 ns | 0.60 | 0.02 | + // UseVector4_SafeRightCorner | 58.97 ns | 0.4152 ns | 0.3884 ns | 0.64 | 0.02 | + // UseVector4_V2 | 41.88 ns | 0.3531 ns | 0.3303 ns | 0.45 | 0.01 | } } \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index 3a3a7d31cd..c0bb25a1b9 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -4,6 +4,7 @@ // using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; +using SixLabors.ImageSharp.Tests.ProfilingBenchmarks; namespace SixLabors.ImageSharp.Sandbox46 { @@ -62,8 +63,8 @@ namespace SixLabors.ImageSharp.Sandbox46 private static void RunDecodeJpegProfilingTests() { Console.WriteLine("RunDecodeJpegProfilingTests..."); - var benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); - foreach (object[] data in JpegProfilingBenchmarks.DecodeJpegData) + var benchmarks = new JpegBenchmarks(new ConsoleOutput()); + foreach (object[] data in JpegBenchmarks.DecodeJpegData) { string fileName = (string)data[0]; benchmarks.DecodeJpeg(fileName); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs similarity index 84% rename from tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index 88959bfabd..3d439c5ce7 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -13,11 +13,11 @@ using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.Formats.Jpg +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { - public class JpegProfilingBenchmarks : MeasureFixture + public class JpegBenchmarks : MeasureFixture { - public JpegProfilingBenchmarks(ITestOutputHelper output) + public JpegBenchmarks(ITestOutputHelper output) : base(output) { } @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Jpeg444, }; - [Theory] // Benchmark, enable manually + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { @@ -69,11 +69,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } // Benchmark, enable manually! - // [Theory] - // [InlineData(1, 75, JpegSubsample.Ratio420)] - // [InlineData(30, 75, JpegSubsample.Ratio420)] - // [InlineData(30, 75, JpegSubsample.Ratio444)] - // [InlineData(30, 100, JpegSubsample.Ratio444)] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] + [InlineData(1, 75, JpegSubsample.Ratio420)] + [InlineData(30, 75, JpegSubsample.Ratio420)] + [InlineData(30, 75, JpegSubsample.Ratio444)] + [InlineData(30, 100, JpegSubsample.Ratio444)] public void EncodeJpeg(int executionCount, int quality, JpegSubsample subsample) { // do not run this on CI even by accident @@ -107,6 +107,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg $@"Encode {testFiles.Length} images" ); } + + foreach (Image image in testImages) + { + image.Dispose(); + } } } diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs similarity index 67% rename from tests/ImageSharp.Tests/ProfilingBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs index bc9b2a947b..3060722768 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs @@ -1,31 +1,23 @@ -using System.IO; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.Primitives; using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { - public class ProfilingBenchmarks : MeasureFixture + public class LoadResizeSaveBenchmarks : MeasureFixture { - public const string SkipProfilingTests = -#if true - null; -#else - "Profiling benchmark, enable manually!"; -#endif - - - public ProfilingBenchmarks(ITestOutputHelper output) + public LoadResizeSaveBenchmarks(ITestOutputHelper output) : base(output) { } - [Theory(Skip = SkipProfilingTests)] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)] public void LoadResizeSave(string imagePath) { diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs new file mode 100644 index 0000000000..267c70219e --- /dev/null +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs @@ -0,0 +1,18 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// Uncomment to enable local profiling benchmarks. DO NOT PUSH TO MAIN! +#define PROFILING + +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks +{ + public static class ProfilingSetup + { + public const string SkipProfilingTests = +#if PROFILING + null; +#else + "Profiling benchmark, enable manually!"; +#endif + } +} \ No newline at end of file From c791579f6e47b8bc68b67fee1910f6886867b8e0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 3 Nov 2018 22:21:48 +0100 Subject: [PATCH 139/238] minor optimization in JpegColorConverter.FromGrayscale --- .../JpegColorConverter.FromGrayScale.cs | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs index 5d7a31a12b..7424145c3b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs @@ -3,6 +3,8 @@ using System; using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { @@ -17,24 +19,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters public override void ConvertToRgba(in ComponentValues values, Span result) { - // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! - ReadOnlySpan yVals = values.Component0; - - var v = new Vector4(0, 0, 0, 1); - var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); + ref float sBase = ref MemoryMarshal.GetReference(values.Component0); + ref Vector4 dBase = ref MemoryMarshal.GetReference(result); + for (int i = 0; i < result.Length; i++) { - float y = yVals[i]; - - v.X = y; - v.Y = y; - v.Z = y; - + var v = new Vector4(Unsafe.Add(ref sBase, i)); + v.W = 1f; v *= scale; - - result[i] = v; + Unsafe.Add(ref dBase, i) = v; } } } From fa092d1511cbaf61c80d69c2257b5d457233ef8e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 00:19:29 +0100 Subject: [PATCH 140/238] add JpegSnoop reports for all current input Jpeg --- .../JpegSnoopReports/Calliphora.jpg.txt | 331 ++++++++ .../JpegSnoopReports/Floorplan.jpg.txt | 266 ++++++ .../JpegSnoopReports/Hiyamugi.jpg.txt | 319 ++++++++ .../baseline/JpegSnoopReports/Lake.jpg.txt | 683 ++++++++++++++++ .../MultiScanBaselineCMYK.jpg.txt | 282 +++++++ .../baseline/JpegSnoopReports/Snake.jpg.txt | 683 ++++++++++++++++ .../baseline/JpegSnoopReports/badeof.jpg.txt | 347 ++++++++ .../baseline/JpegSnoopReports/badrst.jpg.txt | 434 ++++++++++ .../baseline/JpegSnoopReports/cmyk.jpg.txt | 435 ++++++++++ .../baseline/JpegSnoopReports/exif.jpg.txt | 454 ++++++++++ .../gamma_dalai_lama_gray.jpg.txt | 339 ++++++++ .../JpegSnoopReports/jpeg400jfif.jpg.txt | 211 +++++ .../JpegSnoopReports/jpeg420exif.jpg.txt | 412 ++++++++++ .../JpegSnoopReports/jpeg420small.jpg.txt | 330 ++++++++ .../baseline/JpegSnoopReports/jpeg444.jpg.txt | 405 +++++++++ .../JpegSnoopReports/ratio-1x1.jpg.txt | 338 ++++++++ .../JpegSnoopReports/testimgint.jpg.txt | 342 ++++++++ .../JpegSnoopReports/testorig.jpg.txt | 342 ++++++++ .../baseline/JpegSnoopReports/turtle.jpg.txt | 367 +++++++++ .../baseline/JpegSnoopReports/ycck.jpg.txt | 640 +++++++++++++++ ...59-MissingFF00-Progressive-Bedroom.jpg.txt | 461 +++++++++++ ...ue159-MissingFF00-Progressive-Girl.jpg.txt | 520 ++++++++++++ ...ssue178-BadCoeffsProgressive-Lemon.jpg.txt | 471 +++++++++++ .../Issue214-CriticalEOF .jpg.txt | 94 +++ .../Issue385-BadZigZag-Progressive.jpg.txt | 468 +++++++++++ ...e394-MultiHuffmanBaseline-Speakers.jpg.txt | 438 ++++++++++ .../Issue517-No-EOI-Progressive.jpg.txt | 406 +++++++++ .../Issue518-Bad-RST-Progressive.jpg.txt | 759 +++++++++++++++++ .../Issue520-InvalidCast.jpg.txt | 364 +++++++++ ...24-DhtHasWrongLength-Progressive-N.jpg.txt | 284 +++++++ .../Issue694-Decode-Exif-OutOfRange.jpg.txt | 368 +++++++++ .../Issue695-Invalid-EOI.jpg.txt | 39 + .../Issue696-Resize-Exif-OutOfRange.jpg.txt | 377 +++++++++ .../Issue721-InvalidAPP0.jpg.txt | 446 ++++++++++ ...-Ordered-Interleaved-Progressive-A.jpg.txt | 519 ++++++++++++ ...-Ordered-Interleaved-Progressive-B.jpg.txt | 477 +++++++++++ ...-Ordered-Interleaved-Progressive-C.jpg.txt | 484 +++++++++++ .../issue750-exif-load.jpg.txt | 772 ++++++++++++++++++ .../issue750-exif-tranform.jpg.txt | 435 ++++++++++ .../BadEofProgressive.jpg.txt | 452 ++++++++++ .../JpegSnoopReports/ExifUndefType.jpg.txt | 535 ++++++++++++ .../JpegSnoopReports/Festzug.jpg.txt | 459 +++++++++++ .../progressive/JpegSnoopReports/fb.jpg.txt | 525 ++++++++++++ .../JpegSnoopReports/progress.jpg.txt | 468 +++++++++++ 44 files changed, 18581 insertions(+) create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt create mode 100644 tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt create mode 100644 tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt create mode 100644 tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt new file mode 100644 index 0000000000..dc889ab105 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt @@ -0,0 +1,331 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Calliphora.jpg] + Filesize: [254766] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000014 + Comment length = 80 + Comment=File source: http://commons.wikimedia.org/wiki/File:Calliphora_sp_Portrait.jpg + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000066 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 10 16 20 24 + DQT, Row #1: 5 5 6 8 10 23 24 22 + DQT, Row #2: 6 5 6 10 16 23 28 22 + DQT, Row #3: 6 7 9 12 20 35 32 25 + DQT, Row #4: 7 9 15 22 27 44 41 31 + DQT, Row #5: 10 14 22 26 32 42 45 37 + DQT, Row #6: 20 26 31 35 41 48 48 40 + DQT, Row #7: 29 37 38 39 45 40 41 40 + Approx quality factor = 79.94 (scaling=40.12 variance=1.43) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000000AB + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 10 19 40 40 40 40 + DQT, Row #1: 7 8 10 26 40 40 40 40 + DQT, Row #2: 10 10 22 40 40 40 40 40 + DQT, Row #3: 19 26 40 40 40 40 40 40 + DQT, Row #4: 40 40 40 40 40 40 40 40 + DQT, Row #5: 40 40 40 40 40 40 40 40 + DQT, Row #6: 40 40 40 40 40 40 40 40 + DQT, Row #7: 40 40 40 40 40 40 40 40 + Approx quality factor = 79.87 (scaling=40.26 variance=0.36) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000000F0 + Frame header length = 17 + Precision = 8 + Number of Lines = 1198 + Samples per Line = 804 + Image Size = 804 x 1198 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000103 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 00 01 02 03 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000121 + Huffman table length = 79 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 06 31 + Codes of length 07 bits (004 total): 13 22 41 51 + Codes of length 08 bits (004 total): 14 32 61 71 + Codes of length 09 bits (003 total): 07 81 91 + Codes of length 10 bits (006 total): 15 23 42 52 A1 B1 + Codes of length 11 bits (003 total): 33 62 C1 + Codes of length 12 bits (007 total): 16 24 43 72 82 D1 F0 + Codes of length 13 bits (002 total): 25 E1 + Codes of length 14 bits (003 total): 34 53 92 + Codes of length 15 bits (002 total): A2 F1 + Codes of length 16 bits (015 total): 08 63 B2 26 44 C2 D2 73 27 35 55 74 84 93 A3 + Total number of codes: 060 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000172 + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000018E + Huffman table length = 59 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (002 total): 03 31 + Codes of length 06 bits (004 total): 12 41 51 F0 + Codes of length 07 bits (003 total): 04 61 71 + Codes of length 08 bits (008 total): 13 22 81 91 A1 B1 C1 D1 + Codes of length 09 bits (002 total): 32 E1 + Codes of length 10 bits (002 total): 42 F1 + Codes of length 11 bits (002 total): 05 23 + Codes of length 12 bits (002 total): 52 62 + Codes of length 13 bits (002 total): 14 33 + Codes of length 14 bits (001 total): 72 + Codes of length 15 bits (004 total): 24 82 92 A2 + Codes of length 16 bits (003 total): 43 B2 E2 + Total number of codes: 040 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000001CB + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000001D9 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0003E32C.0 + + Compression stats: + Compression Ratio: 11.36:1 + Bits per pixel: 2.11:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2628 ( 17%) + # codes of length 03 bits: 10491 ( 69%) + # codes of length 04 bits: 1319 ( 9%) + # codes of length 05 bits: 611 ( 4%) + # codes of length 06 bits: 101 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 23843 ( 79%) + # codes of length 03 bits: 3770 ( 12%) + # codes of length 04 bits: 1945 ( 6%) + # codes of length 05 bits: 653 ( 2%) + # codes of length 06 bits: 89 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 118632 ( 45%) + # codes of length 03 bits: 34447 ( 13%) + # codes of length 04 bits: 57131 ( 22%) + # codes of length 05 bits: 27139 ( 10%) + # codes of length 06 bits: 8648 ( 3%) + # codes of length 07 bits: 9574 ( 4%) + # codes of length 08 bits: 4195 ( 2%) + # codes of length 09 bits: 1503 ( 1%) + # codes of length 10 bits: 1711 ( 1%) + # codes of length 11 bits: 386 ( 0%) + # codes of length 12 bits: 470 ( 0%) + # codes of length 13 bits: 66 ( 0%) + # codes of length 14 bits: 62 ( 0%) + # codes of length 15 bits: 38 ( 0%) + # codes of length 16 bits: 58 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 58553 ( 58%) + # codes of length 03 bits: 21076 ( 21%) + # codes of length 04 bits: 4270 ( 4%) + # codes of length 05 bits: 6075 ( 6%) + # codes of length 06 bits: 6016 ( 6%) + # codes of length 07 bits: 2009 ( 2%) + # codes of length 08 bits: 2750 ( 3%) + # codes of length 09 bits: 429 ( 0%) + # codes of length 10 bits: 213 ( 0%) + # codes of length 11 bits: 91 ( 0%) + # codes of length 12 bits: 44 ( 0%) + # codes of length 13 bits: 22 ( 0%) + # codes of length 14 bits: 5 ( 0%) + # codes of length 15 bits: 9 ( 0%) + # codes of length 16 bits: 3 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[119] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, 0, 0] RGB=[254,254,254] @ MCU[ 35, 37] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0003E32C.0 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0003E32C + + +*** Searching Compression Signatures *** + + Signature: 01DC499064BA9264D591FDE9071DFD89 + Signature (Rotated): 0175BAF3251040E0EFB2930B73328E7F + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C40Z,D40Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + SW :[Apple ImageIO.framework ] [050 (Normal) ] + SW :[IJG Library ] [080 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [080 ] + SW :[IrfanView ] [080 ] + SW :[idImager ] [080 ] + SW :[FastStone Image Viewer ] [080 ] + SW :[NeatImage ] [080 ] + SW :[Paint.NET ] [080 ] + SW :[Photomatix ] [080 ] + SW :[XnView ] [080 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt new file mode 100644 index 0000000000..2c03157afe --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt @@ -0,0 +1,266 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Floorplan.jpg] + Filesize: [161577] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 13464 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x000A + [Model ] = "Photosmart Plus B209a-m" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Windows Photo Editor 10.0.10011.16384" + [DateTime ] = "2016:01:02 20:17:37" + [ExifOffset ] = @ 0x091A + Offset to Next IFD = 0x000011B6 + + EXIF IFD1 @ Absolute 0x000011D4 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x1214 = @ 0x1232 + [JpegIFByteCount ] = 0x[0000227C] / 8828 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000938 + Dir Length = 0x0008 + [DateTimeOriginal ] = "2016:01:02 19:22:28" + [DateTimeDigitized ] = "2016:01:02 19:22:28" + [SubSecTimeOriginal ] = "00" + [SubSecTimeDigitized ] = "00" + [ColorSpace ] = sRGB + [ExifImageWidth ] = 0x[00000922] / 2338 + [ExifImageHeight ] = 0x[000008C9] / 2249 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000034AE + Length = 12772 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + |Windows Photo Editor 10.0.10011.163842016-01-02T19:22:28 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00006694 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000066D9 + Frame header length = 11 + Precision = 8 + Number of Lines = 645 + Samples per Line = 976 + Image Size = 976 x 645 + Raw Image Orientation = Landscape + Number of Img components = 1 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000066E6 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006707 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000067BE + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000067C8 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00027727.0 + + Compression stats: + Compression Ratio: 4.66:1 + Bits per pixel: 1.72:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 3571 ( 36%) + # codes of length 03 bits: 4320 ( 44%) + # codes of length 04 bits: 925 ( 9%) + # codes of length 05 bits: 456 ( 5%) + # codes of length 06 bits: 313 ( 3%) + # codes of length 07 bits: 291 ( 3%) + # codes of length 08 bits: 6 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 78118 ( 44%) + # codes of length 03 bits: 22349 ( 13%) + # codes of length 04 bits: 35264 ( 20%) + # codes of length 05 bits: 18811 ( 11%) + # codes of length 06 bits: 4312 ( 2%) + # codes of length 07 bits: 8245 ( 5%) + # codes of length 08 bits: 4682 ( 3%) + # codes of length 09 bits: 1584 ( 1%) + # codes of length 10 bits: 1900 ( 1%) + # codes of length 11 bits: 324 ( 0%) + # codes of length 12 bits: 116 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 6 ( 0%) + # codes of length 16 bits: 639 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[231] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1017, 0, 0] RGB=[255,255,255] @ MCU[ 7, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00027726.4 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00027727 + + +*** Searching Compression Signatures *** + + Signature: 015C645021E37D3469A6B652789383DB + Signature (Rotated): 01D400C125EB43B05762A66347B271F7 + File Offset: 0 bytes + Chroma subsampling: Gray + EXIF Make/Model: OK [???] [Photosmart Plus B209a-m] + EXIF Makernotes: NONE + EXIF Software: OK [Windows Photo Editor 10.0.10011.16384] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [090 Gray ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 Gray ] + SW :[IrfanView ] [090 Gray ] + SW :[idImager ] [090 Gray ] + SW :[FastStone Image Viewer ] [090 Gray ] + SW :[NeatImage ] [090 Gray ] + SW :[Paint.NET ] [090 Gray ] + SW :[Photomatix ] [090 Gray ] + SW :[XnView ] [090 Gray ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt new file mode 100644 index 0000000000..8538e13c86 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt @@ -0,0 +1,319 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Hiyamugi.jpg] + Filesize: [540458] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.0] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000014 + Length = 65110 + Identifier = [JFXX] + Not known APP0 type. Skipping remainder. + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x0000FE6C + Comment length = 31 + Comment=LEAD Technologies Inc. V1.01. + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000FE8D + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 2 2 2 2 2 2 2 2 + DQT, Row #1: 2 2 2 2 2 2 2 2 + DQT, Row #2: 2 2 2 2 2 2 2 2 + DQT, Row #3: 2 2 2 2 2 3 3 2 + DQT, Row #4: 2 2 2 2 2 4 4 3 + DQT, Row #5: 2 2 2 2 3 4 4 3 + DQT, Row #6: 2 2 3 3 4 4 4 4 + DQT, Row #7: 2 3 3 3 4 4 4 3 + Approx quality factor = 96.75 (scaling=6.50 variance=21.01) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 2 2 2 2 3 3 3 3 + DQT, Row #1: 2 2 2 2 3 3 3 3 + DQT, Row #2: 2 2 2 3 3 3 3 3 + DQT, Row #3: 2 2 3 3 3 3 3 3 + DQT, Row #4: 3 3 3 3 3 3 3 3 + DQT, Row #5: 3 3 3 3 3 3 3 3 + DQT, Row #6: 3 3 3 3 3 3 3 3 + DQT, Row #7: 3 3 3 3 3 3 3 3 + Approx quality factor = 98.06 (scaling=3.88 variance=4.78) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000FF13 + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000100B7 + Frame header length = 17 + Precision = 8 + Number of Lines = 794 + Samples per Line = 1123 + Image Size = 1123 x 794 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000100CA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000100D8 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00083F28.0 + + Compression stats: + Compression Ratio: 5.64:1 + Bits per pixel: 4.26:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 727 ( 5%) + # codes of length 03 bits: 7443 ( 52%) + # codes of length 04 bits: 2171 ( 15%) + # codes of length 05 bits: 1627 ( 11%) + # codes of length 06 bits: 1355 ( 10%) + # codes of length 07 bits: 785 ( 6%) + # codes of length 08 bits: 92 ( 1%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2590 ( 36%) + # codes of length 03 bits: 1357 ( 19%) + # codes of length 04 bits: 1187 ( 17%) + # codes of length 05 bits: 856 ( 12%) + # codes of length 06 bits: 616 ( 9%) + # codes of length 07 bits: 346 ( 5%) + # codes of length 08 bits: 109 ( 2%) + # codes of length 09 bits: 39 ( 1%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 223973 ( 44%) + # codes of length 03 bits: 69375 ( 14%) + # codes of length 04 bits: 93550 ( 19%) + # codes of length 05 bits: 58421 ( 12%) + # codes of length 06 bits: 13137 ( 3%) + # codes of length 07 bits: 22630 ( 4%) + # codes of length 08 bits: 9176 ( 2%) + # codes of length 09 bits: 6545 ( 1%) + # codes of length 10 bits: 3947 ( 1%) + # codes of length 11 bits: 1890 ( 0%) + # codes of length 12 bits: 1162 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 77 ( 0%) + # codes of length 16 bits: 1763 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 44319 ( 35%) + # codes of length 03 bits: 21048 ( 17%) + # codes of length 04 bits: 24019 ( 19%) + # codes of length 05 bits: 17303 ( 14%) + # codes of length 06 bits: 9470 ( 7%) + # codes of length 07 bits: 2699 ( 2%) + # codes of length 08 bits: 3432 ( 3%) + # codes of length 09 bits: 2092 ( 2%) + # codes of length 10 bits: 717 ( 1%) + # codes of length 11 bits: 679 ( 1%) + # codes of length 12 bits: 85 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 150 ( 0%) + # codes of length 15 bits: 75 ( 0%) + # codes of length 16 bits: 425 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[117] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 812, 102, -218] RGB=[189,244,250] @ MCU[ 19, 16] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00083F27.7 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00083F28 + + +*** Searching Compression Signatures *** + + Signature: 0193B6220463E5A621ED25A53EC2FE7D + Signature (Rotated): 010D9693F4FC34B402EFA979BED34733 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[LEAD Technologies Inc ] [002 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt new file mode 100644 index 0000000000..900f52cb78 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt @@ -0,0 +1,683 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Lake.jpg] + Filesize: [206342] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 10392 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0008 + [Make ] = "Canon" + [Model ] = "Canon EOS DIGITAL REBEL XSi" + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop Camera Raw 9.8 (Windows)" + [DateTime ] = "2016:12:29 12:57:54" + [ExifOffset ] = @ 0x00DE + Offset to Next IFD = 0x000002D6 + + EXIF IFD1 @ Absolute 0x000002E2 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0334 = @ 0x0340 + [JpegIFByteCount ] = 0x[0000255C] / 9564 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000EA + Dir Length = 0x001B + [ExposureTime ] = 1/640 s + [FNumber ] = F8.0 + [ExposureProgram ] = Normal program + [ISOSpeedRatings ] = 200 + [ExifVersion ] = 02.30 + [DateTimeOriginal ] = "2009:07:19 17:00:36" + [DateTimeDigitized ] = "2009:07:19 17:00:36" + [ShutterSpeedValue ] = 9321928/1000000 + [ApertureValue ] = 6/1 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 4/1 + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 200 mm + [SubSecTimeOriginal ] = "73" + [SubSecTimeDigitized ] = "73" + [ColorSpace ] = Uncalibrated + [FocalPlaneXResolution ] = 4272000/878 + [FocalPlaneYResolution ] = 2848000/584 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x0000289C + Length = 9752 + Identifier = [Photoshop 3.0] + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 300 pixels per inch + Width unit = inch + Vertical resolution = 300 pixels per inch + Height unit = inch + 8BIM: [0x0404] Name="" Len=[0x003F] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 4 + IPTC [002:055] Date Created = "20090719" + IPTC [002:060] Time Created = "170036" + IPTC [002:062] Digital Creation Date = "20090719" + IPTC [002:063] Digital Creation Time = "170036" + 8BIM: [0x040C] Name="" Len=[0x2578] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 256 pixels + Height of thumbnail = 171 pixels + Widthbytes = 768 bytes + Total size = 131328 bytes + Size after compression = 9564 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x0000293E + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x52 C5 4C EC 1E FE 25 B8 CA 88 F7 0D 2B 5F 09 F5 | R.L...%.....+_.. + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00004EB6 + Length = 576 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 560 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1999-06-03 00:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'none' (0x6E6F6E65) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000050F8 + Length = 10738 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + | + | + | + | + | + | + | + | + | + | + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00007AEC + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00007B72 + Length = 4 + interval = 160 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00007B78 + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00007B88 + Frame header length = 17 + Precision = 8 + Number of Lines = 853 + Samples per Line = 1280 + Image Size = 1280 x 853 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007B9B + Huffman table length = 159 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 03 + Codes of length 03 bits (003 total): 01 02 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (002 total): 05 41 + Codes of length 07 bits (003 total): 13 22 51 + Codes of length 08 bits (006 total): 32 61 71 81 91 A1 + Codes of length 09 bits (005 total): 06 14 23 42 B1 + Codes of length 10 bits (002 total): 52 C1 + Codes of length 11 bits (004 total): 15 33 62 D1 + Codes of length 12 bits (004 total): 07 72 E1 F1 + Codes of length 13 bits (005 total): 16 24 43 82 F0 + Codes of length 14 bits (003 total): 34 92 A2 + Codes of length 15 bits (000 total): + Codes of length 16 bits (011 total): 53 63 C2 25 73 B2 D2 26 54 93 E2 + Total number of codes: 054 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 02 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 12 21 + Codes of length 07 bits (002 total): 03 31 + Codes of length 08 bits (003 total): 13 41 51 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (000 total): + Codes of length 11 bits (002 total): 04 71 + Codes of length 12 bits (003 total): 14 22 81 + Codes of length 13 bits (001 total): 32 + Codes of length 14 bits (001 total): 42 + Codes of length 15 bits (001 total): 91 + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007C3C + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00007C4A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00032604.0 + + Compression stats: + Compression Ratio: 18.77:1 + Bits per pixel: 1.28:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 8237 ( 48%) + # codes of length 03 bits: 7451 ( 44%) + # codes of length 04 bits: 930 ( 5%) + # codes of length 05 bits: 300 ( 2%) + # codes of length 06 bits: 197 ( 1%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 16681 ( 49%) + # codes of length 02 bits: 10125 ( 30%) + # codes of length 03 bits: 5138 ( 15%) + # codes of length 04 bits: 1825 ( 5%) + # codes of length 05 bits: 432 ( 1%) + # codes of length 06 bits: 39 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 104267 ( 49%) + # codes of length 03 bits: 23564 ( 11%) + # codes of length 04 bits: 44372 ( 21%) + # codes of length 05 bits: 19037 ( 9%) + # codes of length 06 bits: 5565 ( 3%) + # codes of length 07 bits: 5437 ( 3%) + # codes of length 08 bits: 5066 ( 2%) + # codes of length 09 bits: 2163 ( 1%) + # codes of length 10 bits: 491 ( 0%) + # codes of length 11 bits: 407 ( 0%) + # codes of length 12 bits: 211 ( 0%) + # codes of length 13 bits: 115 ( 0%) + # codes of length 14 bits: 36 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 26 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 34240 ( 51%) + # codes of length 02 bits: 15658 ( 24%) + # codes of length 03 bits: 7424 ( 11%) + # codes of length 04 bits: 3865 ( 6%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 3125 ( 5%) + # codes of length 07 bits: 1208 ( 2%) + # codes of length 08 bits: 744 ( 1%) + # codes of length 09 bits: 113 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 60 ( 0%) + # codes of length 12 bits: 60 ( 0%) + # codes of length 13 bits: 9 ( 0%) + # codes of length 14 bits: 4 ( 0%) + # codes of length 15 bits: 1 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[122] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 714, -42, 42] RGB=[224,215,206] @ MCU[113, 24] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 106 + Next position in scan buffer: Offset 0x00032604.0 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00032604 + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000340 + Length: 0x0000255C (9564) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + + * Embedded Thumb Marker: DRI + Length = 4 + + * Embedded Thumb Marker: APP14 + Length = 14 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 171 + Samples per Line = 256 + Image Size = 256 x 171 + + * Embedded Thumb Marker: DHT + Length = 148 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 9212 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01180AF3DE63318828A86409EF4013DD + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [Canon] [Canon EOS DIGITAL REBEL XSi] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop Camera Raw 9.8 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + Appears to be new signature for known software. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt new file mode 100644 index 0000000000..cd415a201a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt @@ -0,0 +1,282 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\MultiScanBaselineCMYK.jpg] + Filesize: [47443] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00000014 + Length = 14 + DCTEncodeVersion = 25600 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 2 [YCCK] + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000024 + Comment length = 38 + Comment=Created by fCoder Graphics Processor + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000004C + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000091 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000000D6 + Frame header length = 20 + Precision = 8 + Number of Lines = 842 + Samples per Line = 595 + Image Size = 595 x 842 + Raw Image Orientation = Portrait + Number of Img components = 4 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cr) + Component[4]: ID=0x04, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (K) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000EC + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000010D + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001C4 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001E5 + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000029C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00005825 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000766A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000A1FA + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x04, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000B951 + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: ?x? + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt new file mode 100644 index 0000000000..926da026fd --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt @@ -0,0 +1,683 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Snake.jpg] + Filesize: [165200] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 11941 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0008 + [Make ] = "Canon" + [Model ] = "Canon EOS DIGITAL REBEL XSi" + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop Camera Raw 9.8 (Windows)" + [DateTime ] = "2016:12:29 12:57:50" + [ExifOffset ] = @ 0x00DE + Offset to Next IFD = 0x000002D6 + + EXIF IFD1 @ Absolute 0x000002E2 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0334 = @ 0x0340 + [JpegIFByteCount ] = 0x[00002B69] / 11113 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000EA + Dir Length = 0x001B + [ExposureTime ] = 1/25 s + [FNumber ] = F4.0 + [ExposureProgram ] = Shutter priority + [ISOSpeedRatings ] = 250 + [ExifVersion ] = 02.30 + [DateTimeOriginal ] = "2009:07:19 13:25:29" + [DateTimeDigitized ] = "2009:07:19 13:25:29" + [ShutterSpeedValue ] = 4643856/1000000 + [ApertureValue ] = 4/1 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 4/1 + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 200 mm + [SubSecTimeOriginal ] = "03" + [SubSecTimeDigitized ] = "03" + [ColorSpace ] = Uncalibrated + [FocalPlaneXResolution ] = 4272000/878 + [FocalPlaneYResolution ] = 2848000/584 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00002EA9 + Length = 11302 + Identifier = [Photoshop 3.0] + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 300 pixels per inch + Width unit = inch + Vertical resolution = 300 pixels per inch + Height unit = inch + 8BIM: [0x0404] Name="" Len=[0x003F] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 4 + IPTC [002:055] Date Created = "20090719" + IPTC [002:060] Time Created = "132529" + IPTC [002:062] Digital Creation Date = "20090719" + IPTC [002:063] Digital Creation Time = "132529" + 8BIM: [0x040C] Name="" Len=[0x2B85] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 256 pixels + Height of thumbnail = 171 pixels + Widthbytes = 768 bytes + Total size = 131328 bytes + Size after compression = 11113 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x00002F4B + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0xEE 2F A2 47 C5 F8 ED 07 08 CD FF 82 A0 D1 7F F2 | ./.G............ + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00005AD1 + Length = 576 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 560 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1999-06-03 00:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'none' (0x6E6F6E65) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00005D13 + Length = 10733 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + | + | + | + | + | + | + | + | + | + | + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00008702 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00008788 + Length = 4 + interval = 160 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0000878E + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000879E + Frame header length = 17 + Precision = 8 + Number of Lines = 853 + Samples per Line = 1280 + Image Size = 1280 x 853 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000087B1 + Huffman table length = 153 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 01 04 05 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 00 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (001 total): 21 + Codes of length 06 bits (003 total): 05 12 31 + Codes of length 07 bits (003 total): 13 41 51 + Codes of length 08 bits (003 total): 06 22 61 + Codes of length 09 bits (003 total): 14 32 71 + Codes of length 10 bits (003 total): 42 81 91 + Codes of length 11 bits (003 total): 15 23 A1 + Codes of length 12 bits (004 total): 07 52 B1 C1 + Codes of length 13 bits (001 total): 33 + Codes of length 14 bits (002 total): 24 43 + Codes of length 15 bits (002 total): 62 D1 + Codes of length 16 bits (011 total): 16 34 72 E1 25 53 63 92 82 A2 F0 + Total number of codes: 045 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 02 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 03 12 21 + Codes of length 07 bits (001 total): 31 + Codes of length 08 bits (000 total): + Codes of length 09 bits (002 total): 04 41 + Codes of length 10 bits (003 total): 13 22 51 + Codes of length 11 bits (000 total): + Codes of length 12 bits (003 total): 32 61 71 + Codes of length 13 bits (000 total): + Codes of length 14 bits (003 total): 05 14 42 + Codes of length 15 bits (000 total): + Codes of length 16 bits (003 total): 81 52 62 + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000884C + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000885A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0002854E.0 + + Compression stats: + Compression Ratio: 25.14:1 + Bits per pixel: 0.95:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 7183 ( 42%) + # codes of length 03 bits: 7286 ( 43%) + # codes of length 04 bits: 1551 ( 9%) + # codes of length 05 bits: 856 ( 5%) + # codes of length 06 bits: 218 ( 1%) + # codes of length 07 bits: 26 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 12266 ( 36%) + # codes of length 02 bits: 11394 ( 33%) + # codes of length 03 bits: 6548 ( 19%) + # codes of length 04 bits: 2911 ( 9%) + # codes of length 05 bits: 875 ( 3%) + # codes of length 06 bits: 241 ( 1%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 59325 ( 45%) + # codes of length 03 bits: 31160 ( 24%) + # codes of length 04 bits: 18131 ( 14%) + # codes of length 05 bits: 4871 ( 4%) + # codes of length 06 bits: 9522 ( 7%) + # codes of length 07 bits: 4029 ( 3%) + # codes of length 08 bits: 2270 ( 2%) + # codes of length 09 bits: 1006 ( 1%) + # codes of length 10 bits: 515 ( 0%) + # codes of length 11 bits: 268 ( 0%) + # codes of length 12 bits: 195 ( 0%) + # codes of length 13 bits: 24 ( 0%) + # codes of length 14 bits: 29 ( 0%) + # codes of length 15 bits: 20 ( 0%) + # codes of length 16 bits: 26 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 34240 ( 51%) + # codes of length 02 bits: 16000 ( 24%) + # codes of length 03 bits: 5994 ( 9%) + # codes of length 04 bits: 5610 ( 8%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 3610 ( 5%) + # codes of length 07 bits: 600 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 410 ( 1%) + # codes of length 10 bits: 200 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 70 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 17 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 6 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[110] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 954, 14, -14] RGB=[244,248,248] @ MCU[124, 21] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 106 + Next position in scan buffer: Offset 0x0002854D.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0002854E + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000340 + Length: 0x00002B69 (11113) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + + * Embedded Thumb Marker: DRI + Length = 4 + + * Embedded Thumb Marker: APP14 + Length = 14 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 171 + Samples per Line = 256 + Image Size = 256 x 171 + + * Embedded Thumb Marker: DHT + Length = 150 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 10759 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01180AF3DE63318828A86409EF4013DD + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [Canon] [Canon EOS DIGITAL REBEL XSi] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop Camera Raw 9.8 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + Appears to be new signature for known software. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt new file mode 100644 index 0000000000..97be4853e6 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt @@ -0,0 +1,347 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\badeof.jpg] + Filesize: [5770] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 149 + Samples per Line = 227 + Image Size = 227 x 149 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D2 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000189 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001AA + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000261 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000026F + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + + Compression stats: + Compression Ratio: 19.73:1 + Bits per pixel: 1.22:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 88 ( 15%) + # codes of length 03 bits: 409 ( 68%) + # codes of length 04 bits: 66 ( 11%) + # codes of length 05 bits: 33 ( 6%) + # codes of length 06 bits: 4 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 134 ( 45%) + # codes of length 03 bits: 68 ( 23%) + # codes of length 04 bits: 60 ( 20%) + # codes of length 05 bits: 26 ( 9%) + # codes of length 06 bits: 12 ( 4%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2706 ( 48%) + # codes of length 03 bits: 636 ( 11%) + # codes of length 04 bits: 1331 ( 23%) + # codes of length 05 bits: 473 ( 8%) + # codes of length 06 bits: 196 ( 3%) + # codes of length 07 bits: 169 ( 3%) + # codes of length 08 bits: 66 ( 1%) + # codes of length 09 bits: 60 ( 1%) + # codes of length 10 bits: 28 ( 0%) + # codes of length 11 bits: 14 ( 0%) + # codes of length 12 bits: 4 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 5 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 697 ( 46%) + # codes of length 03 bits: 243 ( 16%) + # codes of length 04 bits: 294 ( 19%) + # codes of length 05 bits: 164 ( 11%) + # codes of length 06 bits: 68 ( 4%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 35 ( 2%) + # codes of length 09 bits: 4 ( 0%) + # codes of length 10 bits: 2 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[107] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, -9, 0] RGB=[254,254,250] @ MCU[ 4, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001687.2 + + +*** Skipped 1 marker pad bytes *** +*** Marker: ??? (Unknown) (xFF00) *** + OFFSET: 0x00001689 + WARNING: Unknown marker [0xFF00] + Stopping decode + Use [Img Search Fwd/Rev] to locate other valid embedded JPEGs + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + + +*** Additional Info *** +NOTE: Data exists after EOF, range: 0x00000000-0x0000168A (5770 bytes) diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt new file mode 100644 index 0000000000..cb74eb88f5 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt @@ -0,0 +1,434 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\badrst.jpg] + Filesize: [74497] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 8628 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0003 + [Orientation ] = 1 = Row 0: top, Col 0: left + [ExifOffset ] = @ 0x083E + Offset to Next IFD = 0x000010B6 + + EXIF IFD1 @ Absolute 0x000010D4 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x1114 = @ 0x1132 + [JpegIFByteCount ] = 0x[00001097] / 4247 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x0000085C + Dir Length = 0x0005 + [DateTimeOriginal ] = "2016:02:28 11:17:08" + [DateTimeDigitized ] = "2016:02:28 11:17:08" + [SubSecTimeOriginal ] = "06" + [SubSecTimeDigitized ] = "06" + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000021CA + Length = 2464 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + |2016-02-28T11:17:08.057 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002B6C + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002BB1 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00002BF6 + Frame header length = 17 + Precision = 8 + Number of Lines = 480 + Samples per Line = 640 + Image Size = 640 x 480 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002C09 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002C2A + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002CE1 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002D02 + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00002DB9 + Length = 4 + interval = 600 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002DBF + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00002DCD + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Expect Restart interval elapsed @ 0x00008802.4 + ERROR: Restart marker not detected +*** ERROR: Can't find huffman bitstring @ 0x00008802.5, table 0, value [0xffffffe0] +*** ERROR: Bad huffman code @ 0x00008802.4 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,0) @ Offset 0x00008802.5 + MCU located at pixel=(0,240) +*** ERROR: Can't find huffman bitstring @ 0x00008802.6, table 0, value [0xffffffc0] +*** ERROR: Bad huffman code @ 0x00008802.5 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,0) @ Offset 0x00008802.6 + MCU located at pixel=(8,240) +*** ERROR: Can't find huffman bitstring @ 0x00008802.7, table 0, value [0xffffff80] +*** ERROR: Bad huffman code @ 0x00008802.6 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,1) @ Offset 0x00008802.7 + MCU located at pixel=(0,248) +*** ERROR: Can't find huffman bitstring @ 0x00008803.0, table 0, value [0xffffffff] +*** ERROR: Bad huffman code @ 0x00008802.7 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,1) @ Offset 0x00008803.0 + MCU located at pixel=(8,248) +*** ERROR: Can't find huffman bitstring @ 0x00008803.1, table 1, value [0xfffffffe] +*** ERROR: Bad huffman code @ 0x00008803.0 +*** ERROR: Bad scan data in MCU(0,15): Chr(Cb) CSS(0,0) @ Offset 0x00008803.1 + MCU located at pixel=(0,240) +*** ERROR: Can't find huffman bitstring @ 0x00008803.2, table 1, value [0xfffffffc] +*** ERROR: Bad huffman code @ 0x00008803.1 +*** ERROR: Bad scan data in MCU(0,15): Chr(Cr) CSS(0,0) @ Offset 0x00008803.2 + MCU located at pixel=(0,240) +*** ERROR: Can't find huffman bitstring @ 0x00008803.3, table 0, value [0xfffffff8] +*** ERROR: Bad huffman code @ 0x00008803.2 + Only reported first 20 instances of this message... + + Compression stats: + Compression Ratio: 14.80:1 + Bits per pixel: 1.62:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 40 ( 1%) + # codes of length 02 bits: 202 ( 4%) + # codes of length 03 bits: 3515 ( 73%) + # codes of length 04 bits: 423 ( 9%) + # codes of length 05 bits: 338 ( 7%) + # codes of length 06 bits: 228 ( 5%) + # codes of length 07 bits: 54 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 20 ( 1%) + # codes of length 02 bits: 1657 ( 69%) + # codes of length 03 bits: 311 ( 13%) + # codes of length 04 bits: 232 ( 10%) + # codes of length 05 bits: 123 ( 5%) + # codes of length 06 bits: 49 ( 2%) + # codes of length 07 bits: 8 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 32135 ( 43%) + # codes of length 03 bits: 8668 ( 12%) + # codes of length 04 bits: 15771 ( 21%) + # codes of length 05 bits: 7559 ( 10%) + # codes of length 06 bits: 2518 ( 3%) + # codes of length 07 bits: 3834 ( 5%) + # codes of length 08 bits: 1387 ( 2%) + # codes of length 09 bits: 1122 ( 2%) + # codes of length 10 bits: 562 ( 1%) + # codes of length 11 bits: 234 ( 0%) + # codes of length 12 bits: 131 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 57 ( 0%) + # codes of length 16 bits: 286 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 4525 ( 57%) + # codes of length 03 bits: 1153 ( 14%) + # codes of length 04 bits: 1341 ( 17%) + # codes of length 05 bits: 543 ( 7%) + # codes of length 06 bits: 281 ( 4%) + # codes of length 07 bits: 14 ( 0%) + # codes of length 08 bits: 93 ( 1%) + # codes of length 09 bits: 23 ( 0%) + # codes of length 10 bits: 3 ( 0%) + # codes of length 11 bits: 3 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 2 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[103] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1014, -3, -27] RGB=[248,255,252] @ MCU[ 0, 13] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 1 + Next position in scan buffer: Offset 0x0001210E.0 + + +*** Skipped 10 marker pad bytes *** +*** Marker: RST# *** + OFFSET: 0x0000880D + WARNING: Restart marker [0xFFD0] detected outside scan + Stopping decode + Use [Img Search Fwd/Rev] to locate other valid embedded JPEGs + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] Yes + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + + +*** Additional Info *** +NOTE: Data exists after EOF, range: 0x00000000-0x00012301 (74497 bytes) diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt new file mode 100644 index 0000000000..68777cc049 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt @@ -0,0 +1,435 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\cmyk.jpg] + Filesize: [2531270] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00000014 + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 0 [Unknown (RGB or CMYK)] + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000024 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 29 + Profile Size : 1829080 bytes + Preferred CMM Type : 'HDM ' (0x48444D20) + Profile Version : 0.2.4.0 (0x02400000) + Profile Device/Class : Output Device profile ('prtr' (0x70727472)) + Data Colour Space : cmykData ('CMYK' (0x434D594B)) + Profile connection space (PCS) : 'Lab ' (0x4C616220) + Profile creation date : 2007-02-28 08:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : ? (0x00000000) ('....' (0x00000000)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Media-Relative Colorimetric + Profile creator : 'HDM ' (0x48444D20) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000FE1E + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 2 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0001FC18 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 3 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0002FA12 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 4 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0003F80C + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 5 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0004F606 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 6 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0005F400 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 7 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0006F1FA + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 8 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0007EFF4 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 9 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0008EDEE + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 10 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0009EBE8 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 11 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000AE9E2 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 12 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000BE7DC + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 13 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000CE5D6 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 14 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000DE3D0 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 15 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000EE1CA + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 16 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000FDFC4 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 17 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0010DDBE + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 18 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0011DBB8 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 19 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0012D9B2 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 20 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0013D7AC + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 21 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0014D5A6 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 22 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0015D3A0 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 23 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0016D19A + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 24 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0017CF94 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 25 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0018CD8E + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 26 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0019CB88 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 27 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x001AC982 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 28 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x001BC77C + Length = 9096 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 29 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x001BEB06 + Length = 188 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x009F] DefinedName="IPTC-NAA record" + IPTC [002:025] Keywords = "jpeg, productbeelden, productie, ptc, ptc369x1, pulsar" + IPTC [002:210] ? = ??? + IPTC [002:211] ? = ??? + IPTC [002:212] ? = ??? + IPTC [002:213] ? = ??? + IPTC [002:214] ? = ??? + IPTC [002:215] ? = ??? + IPTC [002:216] ? = ??? + IPTC [002:217] ? = ??? + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x001BEBC4 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x001BEC09 + Frame header length = 20 + Precision = 8 + Number of Lines = 900 + Samples per Line = 414 + Image Size = 414 x 900 + Raw Image Orientation = Portrait + Number of Img components = 4 + Component[1]: ID=0x43, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Y) + Component[2]: ID=0x4D, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Cb) + Component[3]: ID=0x59, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Cr) + Component[4]: ID=0x4B, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (K) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001BEC1F + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001BEC40 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001BECF7 + Scan header length = 14 + Number of img components = 4 + Component[1]: selector=0x43, table=0(DC),0(AC) + Component[2]: selector=0x4D, table=0(DC),0(AC) + Component[3]: selector=0x59, table=0(DC),0(AC) + Component[4]: selector=0x4B, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00269FC4 + + +*** Searching Compression Signatures *** + + Signature: 01BC2BB6764A7F9709F829E766D93AAE + Signature (Rotated): 01BC2BB6764A7F9709F829E766D93AAE + File Offset: 0 bytes + Chroma subsampling: ?x? + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [100 Gray ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 Gray ] + SW :[IrfanView ] [100 Gray ] + SW :[idImager ] [100 Gray ] + SW :[FastStone Image Viewer ] [100 Gray ] + SW :[NeatImage ] [100 Gray ] + SW :[Paint.NET ] [100 Gray ] + SW :[Photomatix ] [100 Gray ] + SW :[XnView ] [100 Gray ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt new file mode 100644 index 0000000000..df54994c5e --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt @@ -0,0 +1,454 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\exif.jpg] + Filesize: [32764] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 7678 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0009 + [Make ] = "Canon" + [Model ] = "Canon PowerShot S40" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 180/1 + [YResolution ] = 180/1 + [ResolutionUnit ] = Inch + [DateTime ] = "2003:12:14 12:01:44" + [YCbCrPositioning ] = Centered + [ExifOffset ] = @ 0x00C4 + Offset to Next IFD = 0x000005BE + + EXIF IFD1 @ Absolute 0x000005DC + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 180/1 + [YResolution ] = 180/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x07F4 = @ 0x0812 + [JpegIFByteCount ] = 0x[00001548] / 5448 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000E2 + Dir Length = 0x001F + [ExposureTime ] = 1/500 s + [FNumber ] = F4.9 + [ExifVersion ] = 02.20 + [DateTimeOriginal ] = "2003:12:14 12:01:44" + [DateTimeDigitized ] = "2003:12:14 12:01:44" + [ComponentsConfiguration ] = [Y Cb Cr .] + [CompressedBitsPerPixel ] = 5/1 + [ShutterSpeedValue ] = 287/32 + [ApertureValue ] = 149/32 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 194698/65536 + [MeteringMode ] = CenterWeightedAverage + [Flash ] = Flash did not fire + [FocalLength ] = 21 mm + [MakerNote ] = @ 0x03AE + [UserComment ] = "" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 2272 + [ExifImageHeight ] = 1704 + [ExifInteroperabilityOffset ] = @ 0x0588 + [FocalPlaneXResolution ] = 2272000/280 + [FocalPlaneYResolution ] = 1704000/210 + [FocalPlaneResolutionUnit ] = Inch + [SensingMethod ] = One-chip color area sensor + [FileSource ] = DSC + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [DigitalZoomRatio ] = 2272/2272 + [SceneCaptureType ] = Standard + + EXIF MakerIFD @ Absolute 0x000003CC + Makernote decode option not enabled. + + EXIF InteropIFD @ Absolute 0x000005A6 + Dir Length = 0x0004 + [InteroperabilityIndex ] = "R98" + [InteroperabilityVersion ] = 01.00 + [RelatedImageWidth ] = 2272 + [RelatedImageLength ] = 1704 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00001E14 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00001E59 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00001E9E + Frame header length = 17 + Precision = 8 + Number of Lines = 360 + Samples per Line = 480 + Image Size = 480 x 360 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001EB1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (005 total): 01 02 04 05 06 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001ECF + Huffman table length = 65 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (002 total): 12 21 + Codes of length 06 bits (004 total): 05 31 41 51 + Codes of length 07 bits (004 total): 13 22 61 71 + Codes of length 08 bits (004 total): 06 32 81 91 + Codes of length 09 bits (004 total): 14 42 A1 B1 + Codes of length 10 bits (004 total): 23 52 C1 D1 + Codes of length 11 bits (005 total): 07 15 33 62 E1 + Codes of length 12 bits (003 total): 43 72 F0 + Codes of length 13 bits (003 total): 24 92 F1 + Codes of length 14 bits (004 total): 16 34 53 82 + Codes of length 15 bits (003 total): 25 83 C2 + Codes of length 16 bits (000 total): + Total number of codes: 046 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001F12 + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001F2E + Huffman table length = 45 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (004 total): 04 12 21 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (004 total): 13 22 51 61 + Codes of length 08 bits (002 total): 32 71 + Codes of length 09 bits (002 total): 05 14 + Codes of length 10 bits (002 total): 23 91 + Codes of length 11 bits (001 total): F0 + Codes of length 12 bits (005 total): 33 42 81 A1 B1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001F5D + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00001F6B + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00007FFA.0 + + Compression stats: + Compression Ratio: 20.97:1 + Bits per pixel: 1.14:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 509 ( 18%) + # codes of length 03 bits: 1910 ( 69%) + # codes of length 04 bits: 249 ( 9%) + # codes of length 05 bits: 87 ( 3%) + # codes of length 06 bits: 5 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 905 ( 66%) + # codes of length 03 bits: 213 ( 15%) + # codes of length 04 bits: 169 ( 12%) + # codes of length 05 bits: 84 ( 6%) + # codes of length 06 bits: 9 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 14518 ( 48%) + # codes of length 03 bits: 2881 ( 10%) + # codes of length 04 bits: 6591 ( 22%) + # codes of length 05 bits: 2038 ( 7%) + # codes of length 06 bits: 2356 ( 8%) + # codes of length 07 bits: 926 ( 3%) + # codes of length 08 bits: 484 ( 2%) + # codes of length 09 bits: 220 ( 1%) + # codes of length 10 bits: 149 ( 0%) + # codes of length 11 bits: 76 ( 0%) + # codes of length 12 bits: 27 ( 0%) + # codes of length 13 bits: 14 ( 0%) + # codes of length 14 bits: 8 ( 0%) + # codes of length 15 bits: 3 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2784 ( 53%) + # codes of length 03 bits: 1230 ( 24%) + # codes of length 04 bits: 370 ( 7%) + # codes of length 05 bits: 582 ( 11%) + # codes of length 06 bits: 94 ( 2%) + # codes of length 07 bits: 121 ( 2%) + # codes of length 08 bits: 26 ( 0%) + # codes of length 09 bits: 14 ( 0%) + # codes of length 10 bits: 6 ( 0%) + # codes of length 11 bits: 2 ( 0%) + # codes of length 12 bits: 5 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[122] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, 9, 27] RGB=[255,251,255] @ MCU[ 15, 13] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00007FF9.7 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00007FFA + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000812 + Length: 0x00001548 (5448) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 9 6 5 9 13 22 29 35 + DQT, Row #1: 6 6 8 11 15 33 34 30 + DQT, Row #2: 8 7 9 13 22 33 39 31 + DQT, Row #3: 8 9 12 16 28 49 45 34 + DQT, Row #4: 10 12 21 32 39 61 58 42 + DQT, Row #5: 13 19 31 36 45 58 63 51 + DQT, Row #6: 28 36 44 49 58 68 66 55 + DQT, Row #7: 41 52 54 55 62 56 57 54 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 9 9 12 20 15 26 79 79 + DQT, Row #1: 9 10 12 10 26 26 79 79 + DQT, Row #2: 12 12 10 10 26 79 79 79 + DQT, Row #3: 20 10 10 26 79 79 79 79 + DQT, Row #4: 15 26 26 79 79 79 79 79 + DQT, Row #5: 26 26 79 79 79 79 79 79 + DQT, Row #6: 79 79 79 79 79 79 79 79 + DQT, Row #7: 79 79 79 79 79 79 79 79 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 120 + Samples per Line = 160 + Image Size = 160 x 120 + + * Embedded Thumb Marker: DHT + Length = 418 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 4869 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01D91E583DD0037108266E42ED3A262C + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [Canon] [Canon PowerShot S40] + EXIF Makernotes: OK + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 4 - Uncertain if processed or original + While the EXIF fields indicate original, no compression signatures + in the current database were found matching this make/model + + Appears to be new signature for known camera. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt new file mode 100644 index 0000000000..a5adb0247c --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt @@ -0,0 +1,339 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\gamma_dalai_lama_gray.jpg] + Filesize: [84887] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000014 + Comment length = 46 + Comment= Scaled 1:2 this image wrongly becomes gray. + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000044 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000089 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=1.54 variance=1.58) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000000CE + Frame header length = 17 + Precision = 8 + Number of Lines = 222 + Samples per Line = 258 + Image Size = 258 x 222 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000E1 + Huffman table length = 25 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 01 02 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000FC + Huffman table length = 111 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (002 total): 05 21 + Codes of length 06 bits (007 total): 00 06 12 13 14 31 41 + Codes of length 07 bits (003 total): 22 51 61 + Codes of length 08 bits (007 total): 07 15 16 32 42 71 81 + Codes of length 09 bits (005 total): 08 23 52 62 91 + Codes of length 10 bits (008 total): 33 43 44 72 A1 A2 B1 E3 + Codes of length 11 bits (010 total): 17 24 53 54 55 66 82 92 95 C1 + Codes of length 12 bits (009 total): 18 25 28 34 45 56 63 64 65 + Codes of length 13 bits (014 total): 26 27 46 73 76 85 93 96 A3 A5 A6 C3 C7 D7 + Codes of length 14 bits (010 total): 83 86 B2 B3 B8 C6 D3 D6 E8 F0 + Codes of length 15 bits (011 total): 36 37 48 74 75 84 94 A8 B4 B6 D1 + Codes of length 16 bits (001 total): D2 + Total number of codes: 092 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000016D + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (001 total): 07 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000018A + Huffman table length = 121 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (002 total): 05 11 + Codes of length 05 bits (002 total): 06 21 + Codes of length 06 bits (005 total): 07 08 12 13 31 + Codes of length 07 bits (009 total): 00 09 14 16 17 22 32 41 51 + Codes of length 08 bits (005 total): 0A 15 23 42 61 + Codes of length 09 bits (005 total): 18 24 33 52 71 + Codes of length 10 bits (002 total): 62 81 + Codes of length 11 bits (007 total): 19 34 43 53 72 82 91 + Codes of length 12 bits (007 total): 25 44 54 56 63 A1 A2 + Codes of length 13 bits (014 total): 1A 26 27 28 46 47 55 57 64 73 97 B1 E3 E6 + Codes of length 14 bits (007 total): 35 45 48 58 92 A4 C1 + Codes of length 15 bits (002 total): D8 29 + Codes of length 16 bits (031 total): 67 74 83 85 93 94 B2 36 68 87 88 98 D6 F0 37 39 + 65 66 75 78 84 96 A3 A6 A8 C3 C9 D1 D3 D9 DA + Total number of codes: 102 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000205 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000213 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00014B95.0 + + Compression stats: + Compression Ratio: 2.04:1 + Bits per pixel: 11.78:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 893 ( 97%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 23 ( 2%) + # codes of length 04 bits: 4 ( 0%) + # codes of length 05 bits: 4 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 1728 ( 94%) + # codes of length 02 bits: 46 ( 2%) + # codes of length 03 bits: 30 ( 2%) + # codes of length 04 bits: 18 ( 1%) + # codes of length 05 bits: 14 ( 1%) + # codes of length 06 bits: 6 ( 0%) + # codes of length 07 bits: 4 ( 0%) + # codes of length 08 bits: 2 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 14381 ( 45%) + # codes of length 03 bits: 3819 ( 12%) + # codes of length 04 bits: 4489 ( 14%) + # codes of length 05 bits: 2199 ( 7%) + # codes of length 06 bits: 3836 ( 12%) + # codes of length 07 bits: 911 ( 3%) + # codes of length 08 bits: 1089 ( 3%) + # codes of length 09 bits: 398 ( 1%) + # codes of length 10 bits: 294 ( 1%) + # codes of length 11 bits: 190 ( 1%) + # codes of length 12 bits: 84 ( 0%) + # codes of length 13 bits: 75 ( 0%) + # codes of length 14 bits: 21 ( 0%) + # codes of length 15 bits: 11 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 17100 ( 23%) + # codes of length 03 bits: 31709 ( 42%) + # codes of length 04 bits: 7638 ( 10%) + # codes of length 05 bits: 4203 ( 6%) + # codes of length 06 bits: 6465 ( 9%) + # codes of length 07 bits: 5462 ( 7%) + # codes of length 08 bits: 1472 ( 2%) + # codes of length 09 bits: 804 ( 1%) + # codes of length 10 bits: 206 ( 0%) + # codes of length 11 bits: 296 ( 0%) + # codes of length 12 bits: 156 ( 0%) + # codes of length 13 bits: 164 ( 0%) + # codes of length 14 bits: 47 ( 0%) + # codes of length 15 bits: 7 ( 0%) + # codes of length 16 bits: 55 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[125] (range: 0..255) + + Brightest Pixel Search: + YCC=[ -8, 0, 0] RGB=[127,127,127] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00014B94.4 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00014B95 + + +*** Searching Compression Signatures *** + + Signature: 01BBB1709AC9C1F89220D955A31A8F34 + Signature (Rotated): 01BBB1709AC9C1F89220D955A31A8F34 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[CASIO COMPUTER CO.,LTD ] [EX-Z750 ] [ ] No + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] No + CAM:[PENTAX ] [PENTAX Optio S5i ] [ ] No + CAM:[SIGMA ] [SIGMA SD9 ] [ ] No + SW :[ACDSee ] [100 ] + SW :[Apple ImageIO.framework ] [100 (Best) ] + SW :[Digital Photo Professiona] [10 ] + SW :[IJG Library ] [100 ] + SW :[MS Office Pic Mgr ] [ ] + SW :[Nikon Scan ] [Excellent Qualit] + SW :[Picasa ] [100 (Maximum) ] + SW :[ZoomBrowser EX ] [highest ] + SW :[EOS Viewer Utility ] [ ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 ] + SW :[IrfanView ] [100 ] + SW :[idImager ] [100 ] + SW :[FastStone Image Viewer ] [100 ] + SW :[NeatImage ] [100 ] + SW :[Paint.NET ] [100 ] + SW :[Photomatix ] [100 ] + SW :[XnView ] [100 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt new file mode 100644 index 0000000000..b686b3ce39 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt @@ -0,0 +1,211 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg400jfif.jpg] + Filesize: [45066] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000059 + Frame header length = 11 + Precision = 8 + Number of Lines = 800 + Samples per Line = 600 + Image Size = 600 x 800 + Raw Image Orientation = Portrait + Number of Img components = 1 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00000066 + Length = 4 + interval = 75 + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000006C + Huffman table length = 210 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 04 05 03 02 06 01 00 + Codes of length 04 bits (001 total): 07 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 11 04 00 + Codes of length 05 bits (003 total): 05 21 12 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 51 06 13 61 + Codes of length 08 bits (002 total): 22 71 + Codes of length 09 bits (006 total): 81 14 32 91 A1 07 + Codes of length 10 bits (007 total): 15 B1 42 23 C1 52 D1 + Codes of length 11 bits (003 total): E1 33 16 + Codes of length 12 bits (004 total): 62 F0 24 72 + Codes of length 13 bits (002 total): 82 F1 + Codes of length 14 bits (006 total): 25 43 34 53 92 A2 + Codes of length 15 bits (002 total): B2 63 + Codes of length 16 bits (115 total): 73 C2 35 44 27 93 A3 B3 36 17 54 64 74 C3 D2 E2 + 08 26 83 09 0A 18 19 84 94 45 46 A4 B4 56 D3 55 + 28 1A F2 E3 F3 C4 D4 E4 F4 65 75 85 95 A5 B5 C5 + D5 E5 F5 66 76 86 96 A6 B6 C6 D6 E6 F6 37 47 57 + 67 77 87 97 A7 B7 C7 D7 E7 F7 38 48 58 68 78 88 + 98 A8 B8 C8 D8 E8 F8 29 39 49 59 69 79 89 99 A9 + B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA + DA EA FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000140 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000014A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000B008.0 + + Compression stats: + Compression Ratio: 10.73:1 + Bits per pixel: 0.75:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 7215 ( 96%) + # codes of length 04 bits: 146 ( 2%) + # codes of length 05 bits: 139 ( 2%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 26194 ( 42%) + # codes of length 03 bits: 2772 ( 4%) + # codes of length 04 bits: 16626 ( 27%) + # codes of length 05 bits: 5914 ( 9%) + # codes of length 06 bits: 4996 ( 8%) + # codes of length 07 bits: 2599 ( 4%) + # codes of length 08 bits: 988 ( 2%) + # codes of length 09 bits: 1360 ( 2%) + # codes of length 10 bits: 617 ( 1%) + # codes of length 11 bits: 60 ( 0%) + # codes of length 12 bits: 152 ( 0%) + # codes of length 13 bits: 60 ( 0%) + # codes of length 14 bits: 30 ( 0%) + # codes of length 15 bits: 5 ( 0%) + # codes of length 16 bits: 28 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 58] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 894, 0, 0] RGB=[239,239,239] @ MCU[ 35, 23] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 99 + Next position in scan buffer: Offset 0x0000B007.2 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000B008 + + +*** Searching Compression Signatures *** + + Signature: 01BE82BEB1019CB30EB122273E78E87C + Signature (Rotated): 01BE82BEB1019CB30EB122273E78E87C + File Offset: 0 bytes + Chroma subsampling: Gray + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt new file mode 100644 index 0000000000..babe797d6a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt @@ -0,0 +1,412 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg420exif.jpg] + Filesize: [768608] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 8817 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0008 + [Make ] = "Hewlett-Packard Company" + [Model ] = "HP PhotoSmart 715" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [YCbCrPositioning ] = Centered + [ExifOffset ] = @ 0x006E + Offset to Next IFD = 0x0000018E + + EXIF IFD1 @ Absolute 0x0000019A + Dir Length = 0x0007 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0C07 = @ 0x0C13 + [JpegIFByteCount ] = 0x[00001658] / 5720 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x0000007A + Dir Length = 0x0015 + [ExposureTime ] = 48/10000 s + [FNumber ] = F8.2 + [ISOSpeedRatings ] = 100 + [ExifVersion ] = 02.10 + [DateTimeOriginal ] = "2001:10:02 14:57:31" + [DateTimeDigitized ] = "2001:10:02 14:57:31" + [ComponentsConfiguration ] = [Y Cb Cr .] + [CompressedBitsPerPixel ] = 20/10 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 20/10 + [SubjectDistance ] = 5043/1000 + [MeteringMode ] = CenterWeightedAverage + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 7 mm + [MakerNote ] = @ 0x0282 + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 2048 + [ExifImageHeight ] = 1536 + [ExifInteroperabilityOffset ] = @ 0x0170 + + EXIF MakerIFD @ Absolute 0x0000028E + Makernote decode option not enabled. + + EXIF InteropIFD @ Absolute 0x0000017C + Dir Length = 0x0002 + [InteroperabilityIndex ] = "R98" + [InteroperabilityVersion ] = 01.00 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002275 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 9 11 14 + DQT, Row #1: 3 3 3 4 5 12 13 12 + DQT, Row #2: 3 3 3 5 9 12 15 12 + DQT, Row #3: 3 3 5 6 11 19 18 13 + DQT, Row #4: 3 5 7 12 15 24 23 17 + DQT, Row #5: 5 7 12 14 18 23 25 21 + DQT, Row #6: 11 14 17 19 23 27 27 22 + DQT, Row #7: 16 21 21 22 25 22 23 22 + Approx quality factor = 89.24 (scaling=21.52 variance=2.21) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 3 5 10 22 22 22 22 + DQT, Row #1: 3 5 5 14 22 22 22 22 + DQT, Row #2: 5 5 11 22 22 22 22 22 + DQT, Row #3: 10 14 22 22 22 22 22 22 + DQT, Row #4: 22 22 22 22 22 22 22 22 + DQT, Row #5: 22 22 22 22 22 22 22 22 + DQT, Row #6: 22 22 22 22 22 22 22 22 + DQT, Row #7: 22 22 22 22 22 22 22 22 + Approx quality factor = 89.12 (scaling=21.76 variance=1.62) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000022FB + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000249F + Frame header length = 17 + Precision = 8 + Number of Lines = 1536 + Samples per Line = 2048 + Image Size = 2048 x 1536 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000024B2 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000024C0 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x000BBA5E.0 + + Compression stats: + Compression Ratio: 12.43:1 + Bits per pixel: 1.93:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 4275 ( 9%) + # codes of length 03 bits: 32688 ( 67%) + # codes of length 04 bits: 5786 ( 12%) + # codes of length 05 bits: 3984 ( 8%) + # codes of length 06 bits: 2042 ( 4%) + # codes of length 07 bits: 377 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 16194 ( 66%) + # codes of length 03 bits: 3495 ( 14%) + # codes of length 04 bits: 2416 ( 10%) + # codes of length 05 bits: 1460 ( 6%) + # codes of length 06 bits: 736 ( 3%) + # codes of length 07 bits: 261 ( 1%) + # codes of length 08 bits: 14 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 363342 ( 41%) + # codes of length 03 bits: 113855 ( 13%) + # codes of length 04 bits: 200569 ( 23%) + # codes of length 05 bits: 102577 ( 12%) + # codes of length 06 bits: 32874 ( 4%) + # codes of length 07 bits: 43593 ( 5%) + # codes of length 08 bits: 14054 ( 2%) + # codes of length 09 bits: 8847 ( 1%) + # codes of length 10 bits: 4365 ( 0%) + # codes of length 11 bits: 2009 ( 0%) + # codes of length 12 bits: 770 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 17 ( 0%) + # codes of length 16 bits: 780 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 60258 ( 49%) + # codes of length 03 bits: 17570 ( 14%) + # codes of length 04 bits: 20881 ( 17%) + # codes of length 05 bits: 14001 ( 11%) + # codes of length 06 bits: 6443 ( 5%) + # codes of length 07 bits: 842 ( 1%) + # codes of length 08 bits: 1737 ( 1%) + # codes of length 09 bits: 387 ( 0%) + # codes of length 10 bits: 169 ( 0%) + # codes of length 11 bits: 93 ( 0%) + # codes of length 12 bits: 31 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 2 ( 0%) + # codes of length 15 bits: 5 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[108] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 996, 0, -33] RGB=[244,255,252] @ MCU[ 32, 59] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x000BBA5D.5 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000BBA5E + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000C13 + Length: 0x00001658 (5720) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 10 6 6 10 14 26 32 40 + DQT, Row #1: 8 8 8 12 16 36 38 36 + DQT, Row #2: 8 8 10 14 26 36 44 36 + DQT, Row #3: 8 10 14 18 32 56 52 40 + DQT, Row #4: 10 14 22 36 44 70 66 50 + DQT, Row #5: 14 22 36 42 52 68 74 60 + DQT, Row #6: 32 42 50 56 66 78 78 64 + DQT, Row #7: 46 60 62 64 74 64 66 64 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 10 10 14 30 64 64 64 64 + DQT, Row #1: 10 14 16 42 64 64 64 64 + DQT, Row #2: 14 16 36 64 64 64 64 64 + DQT, Row #3: 30 42 64 64 64 64 64 64 + DQT, Row #4: 64 64 64 64 64 64 64 64 + DQT, Row #5: 64 64 64 64 64 64 64 64 + DQT, Row #6: 64 64 64 64 64 64 64 64 + DQT, Row #7: 64 64 64 64 64 64 64 64 + + * Embedded Thumb Marker: DHT + Length = 418 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 120 + Samples per Line = 160 + Image Size = 160 x 120 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 5141 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 0158E595F22440126FB766B33F56B158 + +*** Searching Compression Signatures *** + + Signature: 010A5B03EB73D6AF719B39FCC8C3AE25 + Signature (Rotated): 011326BE69D2A27FCF4DBCC33DEB07A2 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [Hewlett-Packard Company] [HP PhotoSmart 715] + EXIF Makernotes: OK + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 4 - Uncertain if processed or original + While the EXIF fields indicate original, no compression signatures + in the current database were found matching this make/model + + Appears to be new signature for known camera. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt new file mode 100644 index 0000000000..c001d7297a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt @@ -0,0 +1,330 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg420small.jpg] + Filesize: [5276] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 100 + Samples per Line = 200 + Image Size = 200 x 100 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 00 02 03 05 07 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CF + Huffman table length = 66 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 11 21 + Codes of length 05 bits (002 total): 04 12 + Codes of length 06 bits (004 total): 05 06 31 41 + Codes of length 07 bits (004 total): 07 13 22 51 + Codes of length 08 bits (002 total): 32 61 + Codes of length 09 bits (005 total): 71 72 B1 D1 D2 + Codes of length 10 bits (007 total): 14 23 33 62 81 91 A1 + Codes of length 11 bits (010 total): 15 16 24 25 34 42 44 82 92 A2 + Codes of length 12 bits (007 total): 26 52 53 54 64 94 C2 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 047 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000113 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 06 07 + Codes of length 03 bits (002 total): 04 05 + Codes of length 04 bits (003 total): 00 03 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 02 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000131 + Huffman table length = 63 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 02 + Codes of length 04 bits (002 total): 03 04 + Codes of length 05 bits (004 total): 05 06 11 21 + Codes of length 06 bits (007 total): 07 12 34 51 61 72 B1 + Codes of length 07 bits (014 total): 13 15 16 17 31 32 33 35 41 53 71 91 92 D1 + Codes of length 08 bits (004 total): 22 62 C1 E1 + Codes of length 09 bits (006 total): 14 52 54 81 82 B2 + Codes of length 10 bits (003 total): 36 42 C2 + Codes of length 11 bits (001 total): F0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 044 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000172 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000180 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000149A.0 + + Compression stats: + Compression Ratio: 12.27:1 + Bits per pixel: 1.96:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 69 ( 19%) + # codes of length 03 bits: 232 ( 64%) + # codes of length 04 bits: 34 ( 9%) + # codes of length 05 bits: 19 ( 5%) + # codes of length 06 bits: 10 ( 3%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 76 ( 42%) + # codes of length 03 bits: 60 ( 33%) + # codes of length 04 bits: 36 ( 20%) + # codes of length 05 bits: 5 ( 3%) + # codes of length 06 bits: 5 ( 3%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2698 ( 51%) + # codes of length 03 bits: 506 ( 10%) + # codes of length 04 bits: 1064 ( 20%) + # codes of length 05 bits: 373 ( 7%) + # codes of length 06 bits: 334 ( 6%) + # codes of length 07 bits: 133 ( 3%) + # codes of length 08 bits: 37 ( 1%) + # codes of length 09 bits: 43 ( 1%) + # codes of length 10 bits: 33 ( 1%) + # codes of length 11 bits: 26 ( 0%) + # codes of length 12 bits: 7 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 276 ( 20%) + # codes of length 03 bits: 340 ( 25%) + # codes of length 04 bits: 214 ( 15%) + # codes of length 05 bits: 190 ( 14%) + # codes of length 06 bits: 141 ( 10%) + # codes of length 07 bits: 170 ( 12%) + # codes of length 08 bits: 29 ( 2%) + # codes of length 09 bits: 17 ( 1%) + # codes of length 10 bits: 6 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 86] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 250, -405, 230] RGB=[198,156, 68] @ MCU[ 0, 6] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001499.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000149A + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt new file mode 100644 index 0000000000..06a1ee4263 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt @@ -0,0 +1,405 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg444.jpg] + Filesize: [5667] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.0] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] +Identifier [This is an unknown APP marker. Compliant decoders must ignore it.] not supported. Skipping remainder. + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000005A + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] + Not supported. Skipping remainder. + +*** Marker: APP3 (xFFE3) *** + OFFSET: 0x000000A0 + Length = 68 + +*** Marker: APP4 (xFFE4) *** + OFFSET: 0x000000E6 + Length = 68 + +*** Marker: APP5 (xFFE5) *** + OFFSET: 0x0000012C + Length = 68 + +*** Marker: APP6 (xFFE6) *** + OFFSET: 0x00000172 + Length = 68 + +*** Marker: APP7 (xFFE7) *** + OFFSET: 0x000001B8 + Length = 68 + +*** Marker: APP8 (xFFE8) *** + OFFSET: 0x000001FE + Length = 68 + +*** Marker: APP9 (xFFE9) *** + OFFSET: 0x00000244 + Length = 68 + +*** Marker: APP10 (xFFEA) *** + OFFSET: 0x0000028A + Length = 68 + +*** Marker: APP11 (xFFEB) *** + OFFSET: 0x000002D0 + Length = 68 + +*** Marker: APP12 (xFFEC) *** + OFFSET: 0x00000316 + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] + Not Photoshop DUCKY. Skipping remainder. + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x0000035C + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] + Not Photoshop. Skipping remainder. + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x000003A2 + Length = 68 + DCTEncodeVersion = 26995 + APP14Flags0 = 8289 + APP14Flags1 = 28192 + ColorTransform = 117 [???] + +*** Marker: APP15 (xFFEF) *** + OFFSET: 0x000003E8 + Length = 68 + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000042E + Frame header length = 17 + Precision = 8 + Number of Lines = 256 + Samples per Line = 256 + Image Size = 256 x 256 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x02 (Chrom: Cr) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000441 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000486 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000004CB + Table length = 67 + ---- + Precision=8 bits + Destination ID=2 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000510 + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000006B4 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000006C2 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00001620.0 + + Compression stats: + Compression Ratio: 49.99:1 + Bits per pixel: 0.48:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 992 ( 97%) + # codes of length 03 bits: 31 ( 3%) + # codes of length 04 bits: 0 ( 0%) + # codes of length 05 bits: 1 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1023 ( 50%) + # codes of length 03 bits: 864 ( 42%) + # codes of length 04 bits: 128 ( 6%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 2 ( 0%) + # codes of length 08 bits: 31 ( 2%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 0 ( 0%) + # codes of length 04 bits: 1024 ( 50%) + # codes of length 05 bits: 1024 ( 50%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2048 ( 67%) + # codes of length 03 bits: 1024 ( 33%) + # codes of length 04 bits: 0 ( 0%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[126] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 984,-1026, -999] RGB=[ 75,255, 24] @ MCU[ 0, 31] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0000161F.6 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00001620 + + +*** Searching Compression Signatures *** + + Signature: 019DC7724B5425C464D28F2CF78F707E + Signature (Rotated): 016C4383FFABE35F063D8FCB331942C0 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E4800 ] [NORMAL ] No + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + + +*** Additional Info *** +NOTE: Data exists after EOF, range: 0x00001622-0x00001623 (1 bytes) diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt new file mode 100644 index 0000000000..b2ae24c469 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt @@ -0,0 +1,338 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\ratio-1x1.jpg] + Filesize: [34674] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 4 6 8 10 + DQT, Row #1: 2 2 2 3 4 9 10 9 + DQT, Row #2: 2 2 3 4 6 9 11 9 + DQT, Row #3: 2 3 4 5 8 14 13 10 + DQT, Row #4: 3 4 6 9 11 17 16 12 + DQT, Row #5: 4 6 9 10 13 17 18 15 + DQT, Row #6: 8 10 12 14 16 19 19 16 + DQT, Row #7: 12 15 15 16 18 16 16 16 + Approx quality factor = 91.86 (scaling=16.28 variance=1.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 3 4 8 16 16 16 16 + DQT, Row #1: 3 3 4 11 16 16 16 16 + DQT, Row #2: 4 4 9 16 16 16 16 16 + DQT, Row #3: 8 11 16 16 16 16 16 16 + DQT, Row #4: 16 16 16 16 16 16 16 16 + DQT, Row #5: 16 16 16 16 16 16 16 16 + DQT, Row #6: 16 16 16 16 16 16 16 16 + DQT, Row #7: 16 16 16 16 16 16 16 16 + Approx quality factor = 91.90 (scaling=16.20 variance=0.15) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 769 + Samples per Line = 1900 + Image Size = 1900 x 769 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 07 08 + Codes of length 04 bits (002 total): 06 09 + Codes of length 05 bits (002 total): 04 05 + Codes of length 06 bits (003 total): 01 02 03 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D0 + Huffman table length = 78 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 01 + Codes of length 04 bits (003 total): 02 03 04 + Codes of length 05 bits (003 total): 05 06 11 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (005 total): 08 12 21 31 41 + Codes of length 08 bits (005 total): 13 14 22 51 61 + Codes of length 09 bits (003 total): 15 32 71 + Codes of length 10 bits (009 total): 09 16 23 52 62 81 91 92 A1 + Codes of length 11 bits (005 total): 17 33 42 72 82 + Codes of length 12 bits (005 total): 24 43 54 93 B3 + Codes of length 13 bits (006 total): 63 73 83 A2 B2 C2 + Codes of length 14 bits (003 total): 25 44 A3 + Codes of length 15 bits (009 total): 34 35 36 37 64 76 B1 B4 C1 + Codes of length 16 bits (000 total): + Total number of codes: 059 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000120 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 05 06 07 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 02 03 08 + Codes of length 07 bits (001 total): 01 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000013E + Huffman table length = 64 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 01 + Codes of length 04 bits (002 total): 02 03 + Codes of length 05 bits (003 total): 04 05 11 + Codes of length 06 bits (005 total): 06 21 31 71 81 + Codes of length 07 bits (003 total): 41 51 91 + Codes of length 08 bits (010 total): 12 13 14 22 32 61 A1 B1 C1 D1 + Codes of length 09 bits (005 total): 15 33 42 E1 F0 + Codes of length 10 bits (003 total): 07 23 52 + Codes of length 11 bits (004 total): 43 62 72 82 + Codes of length 12 bits (002 total): 92 F1 + Codes of length 13 bits (001 total): B2 + Codes of length 14 bits (005 total): 16 A2 C2 D2 E2 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 045 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000180 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000018E + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00008770.0 + + Compression stats: + Compression Ratio: 127.89:1 + Bits per pixel: 0.19:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 22539 ( 97%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 379 ( 2%) + # codes of length 04 bits: 246 ( 1%) + # codes of length 05 bits: 91 ( 0%) + # codes of length 06 bits: 69 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 11012 ( 94%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 445 ( 4%) + # codes of length 04 bits: 105 ( 1%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 81 ( 1%) + # codes of length 07 bits: 19 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 23301 ( 56%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 4265 ( 10%) + # codes of length 04 bits: 7407 ( 18%) + # codes of length 05 bits: 3364 ( 8%) + # codes of length 06 bits: 767 ( 2%) + # codes of length 07 bits: 1399 ( 3%) + # codes of length 08 bits: 642 ( 2%) + # codes of length 09 bits: 201 ( 0%) + # codes of length 10 bits: 285 ( 1%) + # codes of length 11 bits: 99 ( 0%) + # codes of length 12 bits: 42 ( 0%) + # codes of length 13 bits: 30 ( 0%) + # codes of length 14 bits: 6 ( 0%) + # codes of length 15 bits: 9 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 11662 ( 60%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 1971 ( 10%) + # codes of length 04 bits: 1938 ( 10%) + # codes of length 05 bits: 1525 ( 8%) + # codes of length 06 bits: 1005 ( 5%) + # codes of length 07 bits: 339 ( 2%) + # codes of length 08 bits: 727 ( 4%) + # codes of length 09 bits: 148 ( 1%) + # codes of length 10 bits: 41 ( 0%) + # codes of length 11 bits: 23 ( 0%) + # codes of length 12 bits: 8 ( 0%) + # codes of length 13 bits: 2 ( 0%) + # codes of length 14 bits: 5 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[250] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1017, 0, 0] RGB=[255,255,255] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0000876F.5 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00008770 + + +*** Searching Compression Signatures *** + + Signature: 01557A9AE226A38386271DFE13D64298 + Signature (Rotated): 0167FCEDBA3A8E8CF822163DB3564762 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Konica Minolta Camera, In] [DiMAGE Z2 ] [ ] No + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[IJG Library ] [092 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [092 ] + SW :[IrfanView ] [092 ] + SW :[idImager ] [092 ] + SW :[FastStone Image Viewer ] [092 ] + SW :[NeatImage ] [092 ] + SW :[Paint.NET ] [092 ] + SW :[Photomatix ] [092 ] + SW :[XnView ] [092 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt new file mode 100644 index 0000000000..ac2b2f9adb --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt @@ -0,0 +1,342 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\testimgint.jpg] + Filesize: [5756] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 149 + Samples per Line = 227 + Image Size = 227 x 149 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D2 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000189 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001AA + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000261 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000026F + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000167A.0 + + Compression stats: + Compression Ratio: 19.78:1 + Bits per pixel: 1.21:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 86 ( 14%) + # codes of length 03 bits: 412 ( 69%) + # codes of length 04 bits: 65 ( 11%) + # codes of length 05 bits: 33 ( 6%) + # codes of length 06 bits: 4 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 132 ( 44%) + # codes of length 03 bits: 70 ( 23%) + # codes of length 04 bits: 60 ( 20%) + # codes of length 05 bits: 26 ( 9%) + # codes of length 06 bits: 12 ( 4%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2692 ( 48%) + # codes of length 03 bits: 628 ( 11%) + # codes of length 04 bits: 1327 ( 23%) + # codes of length 05 bits: 471 ( 8%) + # codes of length 06 bits: 199 ( 4%) + # codes of length 07 bits: 170 ( 3%) + # codes of length 08 bits: 65 ( 1%) + # codes of length 09 bits: 58 ( 1%) + # codes of length 10 bits: 31 ( 1%) + # codes of length 11 bits: 15 ( 0%) + # codes of length 12 bits: 4 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 6 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 689 ( 46%) + # codes of length 03 bits: 244 ( 16%) + # codes of length 04 bits: 289 ( 19%) + # codes of length 05 bits: 158 ( 11%) + # codes of length 06 bits: 70 ( 5%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 36 ( 2%) + # codes of length 09 bits: 5 ( 0%) + # codes of length 10 bits: 1 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[107] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, -9, 0] RGB=[254,254,250] @ MCU[ 4, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001679.6 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000167A + + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt new file mode 100644 index 0000000000..8e339260ba --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt @@ -0,0 +1,342 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\testorig.jpg] + Filesize: [5770] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 149 + Samples per Line = 227 + Image Size = 227 x 149 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D2 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000189 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001AA + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000261 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000026F + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00001688.0 + + Compression stats: + Compression Ratio: 19.73:1 + Bits per pixel: 1.22:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 88 ( 15%) + # codes of length 03 bits: 409 ( 68%) + # codes of length 04 bits: 66 ( 11%) + # codes of length 05 bits: 33 ( 6%) + # codes of length 06 bits: 4 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 134 ( 45%) + # codes of length 03 bits: 68 ( 23%) + # codes of length 04 bits: 60 ( 20%) + # codes of length 05 bits: 26 ( 9%) + # codes of length 06 bits: 12 ( 4%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2706 ( 48%) + # codes of length 03 bits: 636 ( 11%) + # codes of length 04 bits: 1331 ( 23%) + # codes of length 05 bits: 473 ( 8%) + # codes of length 06 bits: 196 ( 3%) + # codes of length 07 bits: 169 ( 3%) + # codes of length 08 bits: 66 ( 1%) + # codes of length 09 bits: 60 ( 1%) + # codes of length 10 bits: 28 ( 0%) + # codes of length 11 bits: 14 ( 0%) + # codes of length 12 bits: 4 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 5 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 697 ( 46%) + # codes of length 03 bits: 243 ( 16%) + # codes of length 04 bits: 294 ( 19%) + # codes of length 05 bits: 164 ( 11%) + # codes of length 06 bits: 68 ( 4%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 35 ( 2%) + # codes of length 09 bits: 4 ( 0%) + # codes of length 10 bits: 2 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[107] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, -9, 0] RGB=[254,254,250] @ MCU[ 4, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001687.2 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00001688 + + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt new file mode 100644 index 0000000000..a8231b19e6 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt @@ -0,0 +1,367 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\turtle.jpg] + Filesize: [55126] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 28 x 28 DPcm (dots per cm) + thumbnail = 0 x 0 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000014 + Length = 3256 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3240 bytes + Preferred CMM Type : 'appl' (0x6170706C) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2012-05-11 16:46:50 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'appl' (0x6170706C) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000CCE + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 4 6 8 10 + DQT, Row #1: 2 2 2 3 4 9 10 9 + DQT, Row #2: 2 2 3 4 6 9 11 9 + DQT, Row #3: 2 3 4 5 8 14 13 10 + DQT, Row #4: 3 4 6 9 11 17 16 12 + DQT, Row #5: 4 6 9 10 13 17 18 15 + DQT, Row #6: 8 10 12 14 16 19 19 16 + DQT, Row #7: 12 15 15 16 18 16 16 16 + Approx quality factor = 91.86 (scaling=16.28 variance=1.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000D13 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 3 4 8 16 16 16 16 + DQT, Row #1: 3 3 4 11 16 16 16 16 + DQT, Row #2: 4 4 9 16 16 16 16 16 + DQT, Row #3: 8 11 16 16 16 16 16 16 + DQT, Row #4: 16 16 16 16 16 16 16 16 + DQT, Row #5: 16 16 16 16 16 16 16 16 + DQT, Row #6: 16 16 16 16 16 16 16 16 + DQT, Row #7: 16 16 16 16 16 16 16 16 + Approx quality factor = 91.90 (scaling=16.20 variance=0.15) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000D58 + Frame header length = 17 + Precision = 8 + Number of Lines = 281 + Samples per Line = 450 + Image Size = 450 x 281 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D6B + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 06 + Codes of length 03 bits (004 total): 00 04 05 07 + Codes of length 04 bits (003 total): 01 03 08 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D8A + Huffman table length = 82 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (003 total): 05 06 11 + Codes of length 05 bits (002 total): 00 12 + Codes of length 06 bits (004 total): 07 13 21 31 + Codes of length 07 bits (003 total): 22 41 51 + Codes of length 08 bits (004 total): 08 14 61 71 + Codes of length 09 bits (006 total): 15 23 32 81 91 A1 + Codes of length 10 bits (007 total): 16 42 52 55 94 B1 D2 + Codes of length 11 bits (004 total): 33 62 72 C1 + Codes of length 12 bits (007 total): 24 34 82 92 A2 D1 F0 + Codes of length 13 bits (005 total): 17 43 53 54 E1 + Codes of length 14 bits (006 total): 09 25 35 83 93 B2 + Codes of length 15 bits (007 total): 18 26 44 64 73 A3 C2 + Codes of length 16 bits (001 total): A4 + Total number of codes: 063 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000DDE + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 04 05 06 07 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000DFC + Huffman table length = 76 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (004 total): 00 03 04 21 + Codes of length 05 bits (003 total): 05 12 31 + Codes of length 06 bits (004 total): 06 41 51 61 + Codes of length 07 bits (006 total): 13 22 71 81 91 A1 + Codes of length 08 bits (006 total): 07 14 32 52 B1 D1 + Codes of length 09 bits (007 total): 15 42 53 62 72 92 C1 + Codes of length 10 bits (005 total): 23 33 A2 E1 F0 + Codes of length 11 bits (005 total): 16 17 34 82 B2 + Codes of length 12 bits (007 total): 24 35 54 63 73 D2 F1 + Codes of length 13 bits (004 total): 08 25 93 C2 + Codes of length 14 bits (003 total): 43 C3 D3 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 057 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E4A + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000E58 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000D754.0 + + Compression stats: + Compression Ratio: 7.37:1 + Bits per pixel: 3.26:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 344 ( 16%) + # codes of length 03 bits: 1157 ( 55%) + # codes of length 04 bits: 453 ( 22%) + # codes of length 05 bits: 102 ( 5%) + # codes of length 06 bits: 32 ( 2%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 216 ( 21%) + # codes of length 03 bits: 672 ( 64%) + # codes of length 04 bits: 77 ( 7%) + # codes of length 05 bits: 59 ( 6%) + # codes of length 06 bits: 20 ( 2%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 11146 ( 23%) + # codes of length 03 bits: 21025 ( 43%) + # codes of length 04 bits: 8376 ( 17%) + # codes of length 05 bits: 3259 ( 7%) + # codes of length 06 bits: 2911 ( 6%) + # codes of length 07 bits: 840 ( 2%) + # codes of length 08 bits: 696 ( 1%) + # codes of length 09 bits: 499 ( 1%) + # codes of length 10 bits: 295 ( 1%) + # codes of length 11 bits: 93 ( 0%) + # codes of length 12 bits: 85 ( 0%) + # codes of length 13 bits: 26 ( 0%) + # codes of length 14 bits: 15 ( 0%) + # codes of length 15 bits: 8 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 5260 ( 31%) + # codes of length 03 bits: 4077 ( 24%) + # codes of length 04 bits: 4031 ( 24%) + # codes of length 05 bits: 1544 ( 9%) + # codes of length 06 bits: 912 ( 5%) + # codes of length 07 bits: 626 ( 4%) + # codes of length 08 bits: 335 ( 2%) + # codes of length 09 bits: 163 ( 1%) + # codes of length 10 bits: 58 ( 0%) + # codes of length 11 bits: 27 ( 0%) + # codes of length 12 bits: 18 ( 0%) + # codes of length 13 bits: 6 ( 0%) + # codes of length 14 bits: 3 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[167] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1017, 3, -3] RGB=[253,255,255] @ MCU[ 26, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0000D753.1 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000D754 + + +*** Searching Compression Signatures *** + + Signature: 01557A9AE226A38386271DFE13D64298 + Signature (Rotated): 0167FCEDBA3A8E8CF822163DB3564762 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Konica Minolta Camera, In] [DiMAGE Z2 ] [ ] No + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[IJG Library ] [092 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [092 ] + SW :[IrfanView ] [092 ] + SW :[idImager ] [092 ] + SW :[FastStone Image Viewer ] [092 ] + SW :[NeatImage ] [092 ] + SW :[Paint.NET ] [092 ] + SW :[Photomatix ] [092 ] + SW :[XnView ] [092 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt new file mode 100644 index 0000000000..717f35f3c9 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt @@ -0,0 +1,640 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\ycck.jpg] + Filesize: [611572] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 4452 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 720000/10000 + [YResolution ] = 720000/10000 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CC 2015.5 (Windows)" + [DateTime ] = "2016:08:23 18:21:25" + [ExifOffset ] = @ 0x00AC + Offset to Next IFD = 0x000000D8 + + EXIF IFD1 @ Absolute 0x000000E4 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0136 = @ 0x0142 + [JpegIFByteCount ] = 0x[00001026] / 4134 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000B8 + Dir Length = 0x0003 + [ColorSpace ] = Uncalibrated + [ExifImageWidth ] = 0x[00000200] / 512 + [ExifImageHeight ] = 0x[00000200] / 512 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00001168 + Length = 6522 + Identifier = [Photoshop 3.0] + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ + 8BIM: [0x043A] Name="" Len=[0x00E5] DefinedName="Print Information" + Print Information = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 0B 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 00 00 00 05 00 00 00 | intOutput....... + | 0x00 50 73 74 53 62 6F 6F 6C 01 00 00 00 00 49 6E | .PstSbool.....In + | 0x74 65 65 6E 75 6D 00 00 00 00 49 6E 74 65 00 00 | teenum....Inte.. + | 0x00 00 43 6C 72 6D 00 00 00 0F 70 72 69 6E 74 53 | ..Clrm....printS + | 0x69 78 74 65 65 6E 42 69 74 62 6F 6F 6C 00 00 00 | ixteenBitbool... + | 0x00 0B 70 72 69 6E 74 65 72 4E 61 6D 65 54 45 58 | ..printerNameTEX + | 0x54 00 00 00 01 00 00 00 00 00 0F 70 72 69 6E 74 | T..........print + | ... + 8BIM: [0x043B] Name="" Len=[0x022D] DefinedName="Print Style" + Print Style = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 12 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 4F 70 74 69 6F 6E 73 | intOutputOptions + | 0x00 00 00 17 00 00 00 00 43 70 74 6E 62 6F 6F 6C | ........Cptnbool + | 0x00 00 00 00 00 43 6C 62 72 62 6F 6F 6C 00 00 00 | .....Clbrbool... + | 0x00 00 52 67 73 4D 62 6F 6F 6C 00 00 00 00 00 43 | ..RgsMbool.....C + | 0x72 6E 43 62 6F 6F 6C 00 00 00 00 00 43 6E 74 43 | rnCbool.....CntC + | 0x62 6F 6F 6C 00 00 00 00 00 4C 62 6C 73 62 6F 6F | bool.....Lblsboo + | 0x6C 00 00 00 00 00 4E 67 74 76 62 6F 6F 6C 00 00 | l.....Ngtvbool.. + | ... + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 72 pixels per inch + Width unit = cm + Vertical resolution = 72 pixels per inch + Height unit = cm + 8BIM: [0x0426] Name="" Len=[0x000E] DefinedName="Print scale" + Style = centered + X location = 0.00000 + Y location = 0.00000 + Scale = 1.00000 + 8BIM: [0x040D] Name="" Len=[0x0004] DefinedName="Global Angle" + Global Angle = 30 degrees + 8BIM: [0x0419] Name="" Len=[0x0004] DefinedName="Global Altitude" + Global Altitude = 30 + 8BIM: [0x03F3] Name="" Len=[0x0009] DefinedName="Print flags" + Labels = false + Crop marks = false + Color bars = false + Registration marks = false + Negative = false + Flip = false + Interpolate = false + Caption = false + Print flags = true + 8BIM: [0x2710] Name="" Len=[0x000A] DefinedName="Print flags information" + Version = 1 + Center crop marks = 0 + Reserved = 0 + Bleed width value = 0 + Bleed width scale = 2 + 8BIM: [0x03F5] Name="" Len=[0x0048] DefinedName="Color halftoning information" + Color halftoning information = + | 0x00 2F 66 66 00 01 00 6C 66 66 00 06 00 00 00 00 | ./ff...lff...... + | 0x00 01 00 2F 66 66 00 01 00 A1 99 9A 00 06 00 00 | .../ff.......... + | 0x00 00 00 01 00 32 00 00 00 01 00 5A 00 00 00 06 | .....2.....Z.... + | 0x00 00 00 00 00 01 00 35 00 00 00 01 00 2D 00 00 | .......5.....-.. + | 0x00 06 00 00 00 00 00 01 | ........ + 8BIM: [0x03F8] Name="" Len=[0x0070] DefinedName="Color transfer functions" + Color transfer functions = + | 0x00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF 03 E8 00 00 00 00 FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF 03 E8 00 00 00 00 FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0x03 E8 00 00 00 00 FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF 03 E8 00 00 | ................ + 8BIM: [0x0400] Name="" Len=[0x0002] DefinedName="Layer state information" + Target layer = 0 + 8BIM: [0x0402] Name="" Len=[0x0002] DefinedName="Layers group information" + Layer #0: + Layer Group = 0 + 8BIM: [0x0430] Name="" Len=[0x0001] DefinedName="Layer Groups Enabled ID" + Layer #0: + Layer Group Enabled ID = 1 + 8BIM: [0x042D] Name="" Len=[0x0006] DefinedName="Layer Selection IDs" + Num selected = 1 + Layer ID = 3 + 8BIM: [0x0408] Name="" Len=[0x0010] DefinedName="Grid and guides information" + Version = 1 + Grid Horizontal = 576 + Grid Vertical = 576 + Number of Guide Resources = 0 + 8BIM: [0x041E] Name="" Len=[0x0004] DefinedName="URL List" + URL List = | 0x00 00 00 00 | .... + 8BIM: [0x041A] Name="" Len=[0x0363] DefinedName="Slices" + Slice Header: + Version = 6 + Bound Rect (top) = 0 + Bound Rect (left) = 0 + Bound Rect (bottom) = 512 + Bound Rect (right) = 512 + Name of group of slices = "imageprocessor-logo-512" + Number of slices = 1 + ----- + Slice #0: + Slice Resource: + ID = 0 + Group ID = 0 + Origin = 0 + Name = "" + Type = 1 + Position (top) = 0 + Position (left) = 0 + Position (bottom) = 512 + Position (right) = 512 + URL = "" + Target = "" + Message = "" + Alt Tag = "" + Cell text is HTML = true + Cell text = "" + Horizontal alignment = 0 + Vertical alignment = 0 + Alpha color = 0 + Red = 0 + Green = 0 + Blue = 0 + Descriptor version = 16 + Descriptor: + Name from classID = "" + classID = "null" + Num items in descriptor = 2 + ----- + Descriptor item #0: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 512 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 512 + ----- + Descriptor item #1: + Key = "slices" + OSType key = "VlLs" + Num items in list = 1 + ----- + Item #0: + OSType key = "" + Descriptor: + Name from classID = "" + classID = "slice" + Num items in descriptor = 18 + ----- + Descriptor item #0: + Key = "sliceID" + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "groupID" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "origin" + OSType key = "enum" + Type = "ESliceOrigin" + Enum = "autoGenerated" + Descriptor item #3: + Key = "Type" + OSType key = "enum" + Type = "ESliceType" + Enum = "Img " + Descriptor item #4: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 512 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 512 + ----- + Descriptor item #5: + Key = "url" + OSType key = "TEXT" + String = "" + Descriptor item #6: + Key = "null" + OSType key = "TEXT" + String = "" + Descriptor item #7: + Key = "Msge" + OSType key = "TEXT" + String = "" + Descriptor item #8: + Key = "altTag" + OSType key = "TEXT" + String = "" + Descriptor item #9: + Key = "cellTextIsHTML" + OSType key = "bool" + Value = true + Descriptor item #10: + Key = "cellText" + OSType key = "TEXT" + String = "" + Descriptor item #11: + Key = "horzAlign" + OSType key = "enum" + Type = "ESliceHorzAlign" + Enum = "default" + Descriptor item #12: + Key = "vertAlign" + OSType key = "enum" + Type = "ESliceVertAlign" + Enum = "default" + Descriptor item #13: + Key = "bgColorType" + OSType key = "enum" + Type = "ESliceBGColorType" + Enum = "None" + Descriptor item #14: + Key = "topOutset" + OSType key = "long" + Value = 0 + Descriptor item #15: + Key = "leftOutset" + OSType key = "long" + Value = 0 + Descriptor item #16: + Key = "bottomOutset" + OSType key = "long" + Value = 0 + Descriptor item #17: + Key = "rightOutset" + OSType key = "long" + Value = 0 + ----- + ----- + ----- + ----- + 8BIM: [0x0428] Name="" Len=[0x000C] DefinedName="Pixel Aspect Ratio" + Version = 2 + X/Y Ratio = 1.00000 + 8BIM: [0x0414] Name="" Len=[0x0004] DefinedName="Document-specific IDs seed number" + Base value = 3 + 8BIM: [0x040C] Name="" Len=[0x1042] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 160 pixels + Height of thumbnail = 160 pixels + Widthbytes = 480 bytes + Total size = 76800 bytes + Size after compression = 4134 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x00001A3C + 8BIM: [0x0421] Name="" Len=[0x0061] DefinedName="Version Info" + Version = 1 + hasRealMergedData = 1 + Writer name = "Adobe Photoshop" + Reader name = "Adobe Photoshop CC 2015.5" + File version = 1 + 8BIM: [0x0406] Name="" Len=[0x0007] DefinedName="JPEG quality" + Photoshop Save As Quality = 8 + Photoshop Save Format = "Standard" + Photoshop Save Progressive Scans = "3 Scans" + ??? = 1 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00002AE4 + Length = 3685 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000394B + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 9 + Profile Size : 557168 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Output Device profile ('prtr' (0x70727472)) + Data Colour Space : cmykData ('CMYK' (0x434D594B)) + Profile connection space (PCS) : 'Lab ' (0x4C616220) + Profile creation date : 2000-07-26 05:41:53 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'ADBE' (0x41444245) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Media-Relative Colorimetric + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0001392F + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 2 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00023913 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 3 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000338F7 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 4 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000438DB + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 5 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000538BF + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 6 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000638A3 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 7 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00073887 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 8 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0008386B + Length = 33264 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 9 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0008BA5D + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 2 [YCCK] + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0008BA6D + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0008BAF3 + Frame header length = 20 + Precision = 8 + Number of Lines = 512 + Samples per Line = 512 + Image Size = 512 x 512 + Raw Image Orientation = Landscape + Number of Img components = 4 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cr) + Component[4]: ID=0x04, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (K) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x0008BB09 + Length = 4 + interval = 64 + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0008BB0F + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 04 05 03 02 06 01 00 + Codes of length 04 bits (001 total): 07 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 04 05 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 11 04 00 + Codes of length 05 bits (003 total): 05 21 12 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 51 06 13 61 + Codes of length 08 bits (002 total): 22 71 + Codes of length 09 bits (006 total): 81 14 32 91 A1 07 + Codes of length 10 bits (007 total): 15 B1 42 23 C1 52 D1 + Codes of length 11 bits (003 total): E1 33 16 + Codes of length 12 bits (004 total): 62 F0 24 72 + Codes of length 13 bits (002 total): 82 F1 + Codes of length 14 bits (006 total): 25 43 34 53 92 A2 + Codes of length 15 bits (002 total): B2 63 + Codes of length 16 bits (115 total): 73 C2 35 44 27 93 A3 B3 36 17 54 64 74 C3 D2 E2 + 08 26 83 09 0A 18 19 84 94 45 46 A4 B4 56 D3 55 + 28 1A F2 E3 F3 C4 D4 E4 F4 65 75 85 95 A5 B5 C5 + D5 E5 F5 66 76 86 96 A6 B6 C6 D6 E6 F6 37 47 57 + 67 77 87 97 A7 B7 C7 D7 E7 F7 38 48 58 68 78 88 + 98 A8 B8 C8 D8 E8 F8 29 39 49 59 69 79 89 99 A9 + B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA + DA EA FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (002 total): 04 21 + Codes of length 06 bits (003 total): 12 31 41 + Codes of length 07 bits (005 total): 05 51 13 61 22 + Codes of length 08 bits (005 total): 06 71 81 91 32 + Codes of length 09 bits (004 total): A1 B1 F0 14 + Codes of length 10 bits (005 total): C1 D1 E1 23 42 + Codes of length 11 bits (006 total): 15 52 62 72 F1 33 + Codes of length 12 bits (004 total): 24 34 43 82 + Codes of length 13 bits (008 total): 16 92 53 25 A2 63 B2 C2 + Codes of length 14 bits (003 total): 07 73 D2 + Codes of length 15 bits (003 total): 35 E2 44 + Codes of length 16 bits (109 total): 83 17 54 93 08 09 0A 18 19 26 36 45 1A 27 64 74 + 55 37 F2 A3 B3 C3 28 29 D3 E3 F3 84 94 A4 B4 C4 + D4 E4 F4 65 75 85 95 A5 B5 C5 D5 E5 F5 46 56 66 + 76 86 96 A6 B6 C6 D6 E6 F6 47 57 67 77 87 97 A7 + B7 C7 D7 E7 F7 38 48 58 68 78 88 98 A8 B8 C8 D8 + E8 F8 39 49 59 69 79 89 99 A9 B9 C9 D9 E9 F9 2A + 3A 4A 5A 6A 7A 8A 9A AA BA CA DA EA FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0008BCB3 + Scan header length = 14 + Number of img components = 4 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Component[4]: selector=0x04, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000954F2 + + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: ?x? + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CC 2015.5 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + NOTE: Photoshop IRB detected + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt new file mode 100644 index 0000000000..ea1f5e0f79 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt @@ -0,0 +1,461 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue159-MissingFF00-Progressive-Bedroom.jpg] + Filesize: [338422] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 14 18 22 + DQT, Row #1: 4 4 5 7 9 21 22 20 + DQT, Row #2: 5 5 6 9 14 21 25 20 + DQT, Row #3: 5 6 8 10 18 31 29 22 + DQT, Row #4: 6 8 13 20 24 39 37 28 + DQT, Row #5: 9 13 20 23 29 37 41 33 + DQT, Row #6: 18 23 28 31 37 44 43 36 + DQT, Row #7: 26 33 34 35 40 36 37 36 + Approx quality factor = 81.99 (scaling=36.03 variance=1.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 6 6 9 17 36 36 36 36 + DQT, Row #1: 6 8 9 24 36 36 36 36 + DQT, Row #2: 9 9 20 36 36 36 36 36 + DQT, Row #3: 17 24 36 36 36 36 36 36 + DQT, Row #4: 36 36 36 36 36 36 36 36 + DQT, Row #5: 36 36 36 36 36 36 36 36 + DQT, Row #6: 36 36 36 36 36 36 36 36 + DQT, Row #7: 36 36 36 36 36 36 36 36 + Approx quality factor = 81.88 (scaling=36.24 variance=0.48) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 2300 + Samples per Line = 2300 + Image Size = 2300 x 2300 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 27 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 01 02 + Codes of length 04 bits (003 total): 03 04 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CE + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000EA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000CBBB + Huffman table length = 56 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (004 total): 00 01 02 03 + Codes of length 04 bits (005 total): 04 10 11 12 41 + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (005 total): 05 13 20 22 32 + Codes of length 07 bits (003 total): 15 30 42 + Codes of length 08 bits (005 total): 14 23 33 34 50 + Codes of length 09 bits (000 total): + Codes of length 10 bits (002 total): 24 40 + Codes of length 11 bits (002 total): 06 16 + Codes of length 12 bits (002 total): 43 60 + Codes of length 13 bits (002 total): 70 A0 + Codes of length 14 bits (003 total): 44 80 90 + Codes of length 15 bits (001 total): B0 + Codes of length 16 bits (001 total): 35 + Total number of codes: 037 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000CBF5 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001A2A8 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (005 total): 02 03 10 20 30 + Codes of length 05 bits (003 total): 12 13 31 + Codes of length 06 bits (004 total): 04 21 32 40 + Codes of length 07 bits (002 total): 14 51 + Codes of length 08 bits (002 total): 05 41 + Codes of length 09 bits (002 total): 33 50 + Codes of length 10 bits (001 total): 22 + Codes of length 11 bits (004 total): 15 52 61 70 + Codes of length 12 bits (003 total): 23 42 60 + Codes of length 13 bits (000 total): + Codes of length 14 bits (003 total): 71 A0 B0 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001A2DD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001BB1E + Huffman table length = 50 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (005 total): 02 03 10 20 30 + Codes of length 05 bits (003 total): 12 13 31 + Codes of length 06 bits (004 total): 04 21 32 40 + Codes of length 07 bits (002 total): 14 51 + Codes of length 08 bits (003 total): 05 41 50 + Codes of length 09 bits (001 total): 22 + Codes of length 10 bits (000 total): + Codes of length 11 bits (001 total): 61 + Codes of length 12 bits (004 total): 23 33 60 70 + Codes of length 13 bits (002 total): 15 43 + Codes of length 14 bits (003 total): 52 A0 B0 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001BB52 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001D49C + Huffman table length = 67 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (000 total): + Codes of length 04 bits (004 total): 10 11 21 31 + Codes of length 05 bits (005 total): 02 41 51 71 81 + Codes of length 06 bits (001 total): 20 + Codes of length 07 bits (006 total): 12 22 30 61 91 A1 + Codes of length 08 bits (004 total): 03 32 33 C1 + Codes of length 09 bits (002 total): 40 50 + Codes of length 10 bits (010 total): 13 23 42 52 72 82 B1 D1 E1 F0 + Codes of length 11 bits (002 total): 34 62 + Codes of length 12 bits (003 total): 60 92 F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (002 total): 24 80 + Codes of length 15 bits (000 total): + Codes of length 16 bits (007 total): 04 70 43 A2 14 C0 D0 + Total number of codes: 048 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001D4E1 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000291D6 + Huffman table length = 44 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 31 41 + Codes of length 05 bits (001 total): 51 + Codes of length 06 bits (003 total): 10 61 71 + Codes of length 07 bits (003 total): 81 91 A1 + Codes of length 08 bits (003 total): 20 B1 F0 + Codes of length 09 bits (004 total): 30 C1 D1 E1 + Codes of length 10 bits (003 total): 40 50 F1 + Codes of length 11 bits (001 total): 60 + Codes of length 12 bits (001 total): 70 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 025 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00029204 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00044080 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00047DC7 + Huffman table length = 45 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (004 total): 10 30 31 61 + Codes of length 05 bits (006 total): 20 21 40 41 51 71 + Codes of length 06 bits (002 total): 50 60 + Codes of length 07 bits (003 total): 81 91 A1 + Codes of length 08 bits (001 total): B1 + Codes of length 09 bits (000 total): + Codes of length 10 bits (002 total): 70 F0 + Codes of length 11 bits (002 total): C1 D1 + Codes of length 12 bits (003 total): A0 B0 F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00047DF6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00048BD6 + Huffman table length = 45 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (004 total): 20 30 31 61 + Codes of length 05 bits (006 total): 10 21 40 41 51 71 + Codes of length 06 bits (002 total): 50 81 + Codes of length 07 bits (003 total): 60 91 B1 + Codes of length 08 bits (001 total): A1 + Codes of length 09 bits (000 total): + Codes of length 10 bits (002 total): 70 C1 + Codes of length 11 bits (002 total): 80 F0 + Codes of length 12 bits (003 total): A0 B0 D1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00048C05 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00049AE7 + Huffman table length = 48 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 70 + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (007 total): 01 11 31 41 51 80 91 + Codes of length 05 bits (003 total): 10 21 81 + Codes of length 06 bits (002 total): 50 60 + Codes of length 07 bits (005 total): 20 40 61 71 D1 + Codes of length 08 bits (004 total): 30 B1 E1 F1 + Codes of length 09 bits (002 total): A1 F0 + Codes of length 10 bits (003 total): A0 C0 C1 + Codes of length 11 bits (001 total): D0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 029 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00049B19 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000529F4 + + +*** Searching Compression Signatures *** + + Signature: 0138A8D4ECE59F41D2EB9AF5168B6675 + Signature (Rotated): 01CA9A809F737BA668C16DDE52E74092 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] No + SW :[IJG Library ] [082 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [082 ] + SW :[IrfanView ] [082 ] + SW :[idImager ] [082 ] + SW :[FastStone Image Viewer ] [082 ] + SW :[NeatImage ] [082 ] + SW :[Paint.NET ] [082 ] + SW :[Photomatix ] [082 ] + SW :[XnView ] [082 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt new file mode 100644 index 0000000000..4858b4ea18 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt @@ -0,0 +1,520 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue159-MissingFF00-Progressive-Girl.jpg] + Filesize: [60927] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000014 + Length = 132 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x0067] DefinedName="IPTC-NAA record" + IPTC [002:040] Special Instructions = "FBMD01000a820d0000192d00007a4400006e460000a9470000a44e00000b7b0000cc830000e0880000a08c0000ffed0000" + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000009A + Length = 3064 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3048 bytes + Preferred CMM Type : '....' (0x00000000) + Profile Version : 0.2.0.0 (0x02000000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2009-03-27 21:36:31 + Profile file signature : 'acsp' (0x61637370) + Primary platform : ? (0x00000000) ('....' (0x00000000)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000001_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : '....' (0x00000000) + Profile ID : 0x29F83DDE_AFF255AE_7842FAE4_CA83390D + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000C94 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 9 6 6 9 14 23 30 35 + DQT, Row #1: 7 7 8 11 15 34 35 32 + DQT, Row #2: 8 8 9 14 23 33 40 32 + DQT, Row #3: 8 10 13 17 30 50 46 36 + DQT, Row #4: 10 13 21 32 39 63 60 45 + DQT, Row #5: 14 20 32 37 47 60 66 53 + DQT, Row #6: 28 37 45 50 60 70 70 59 + DQT, Row #7: 42 53 55 57 65 58 60 57 + Approx quality factor = 71.07 (scaling=57.86 variance=0.92) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000CD9 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 10 10 14 27 57 57 57 57 + DQT, Row #1: 10 12 15 38 57 57 57 57 + DQT, Row #2: 14 15 32 57 57 57 57 57 + DQT, Row #3: 27 38 57 57 57 57 57 57 + DQT, Row #4: 57 57 57 57 57 57 57 57 + DQT, Row #5: 57 57 57 57 57 57 57 57 + DQT, Row #6: 57 57 57 57 57 57 57 57 + DQT, Row #7: 57 57 57 57 57 57 57 57 + Approx quality factor = 71.23 (scaling=57.54 variance=0.18) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x00000D1E + Frame header length = 17 + Precision = 8 + Number of Lines = 990 + Samples per Line = 750 + Image Size = 750 x 990 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D31 + Huffman table length = 27 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D4E + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D68 + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000D82 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002CED + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (003 total): 03 10 11 + Codes of length 05 bits (003 total): 04 12 20 + Codes of length 06 bits (004 total): 21 30 31 40 + Codes of length 07 bits (002 total): 32 41 + Codes of length 08 bits (002 total): 13 22 + Codes of length 09 bits (003 total): 05 14 50 + Codes of length 10 bits (001 total): 33 + Codes of length 11 bits (001 total): 42 + Codes of length 12 bits (001 total): 23 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002D19 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00004455 + Huffman table length = 35 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (005 total): 02 10 11 20 30 + Codes of length 05 bits (001 total): 40 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 12 50 + Codes of length 08 bits (003 total): 03 31 41 + Codes of length 09 bits (001 total): 21 + Codes of length 10 bits (001 total): 51 + Codes of length 11 bits (001 total): 60 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 016 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000447A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000464C + Huffman table length = 32 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (000 total): + Codes of length 04 bits (007 total): 00 10 11 20 30 40 50 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 12 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 21 31 70 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000466E + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00004775 + Huffman table length = 50 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (003 total): 02 21 40 + Codes of length 05 bits (007 total): 10 12 30 31 32 50 91 + Codes of length 06 bits (003 total): 20 41 51 + Codes of length 07 bits (003 total): 60 61 71 + Codes of length 08 bits (004 total): 03 22 42 81 + Codes of length 09 bits (002 total): 13 62 + Codes of length 10 bits (001 total): 43 + Codes of length 11 bits (005 total): 23 52 70 80 A1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000047A9 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00004E79 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (003 total): 10 21 31 + Codes of length 05 bits (004 total): 41 61 71 81 + Codes of length 06 bits (002 total): 20 51 + Codes of length 07 bits (002 total): 30 91 + Codes of length 08 bits (003 total): A1 D1 F0 + Codes of length 09 bits (001 total): 40 + Codes of length 10 bits (001 total): B1 + Codes of length 11 bits (001 total): C1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): E1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00004EA4 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007B0B + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000083AB + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 11 20 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 21 30 31 + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (001 total): 51 + Codes of length 09 bits (001 total): 40 + Codes of length 10 bits (001 total): 61 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000083CC + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000088BF + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 00 10 11 + Codes of length 04 bits (001 total): 20 + Codes of length 05 bits (001 total): 30 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 21 31 41 + Codes of length 08 bits (001 total): 40 + Codes of length 09 bits (001 total): 51 + Codes of length 10 bits (001 total): 71 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000088E0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008C75 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (003 total): 10 71 81 + Codes of length 08 bits (003 total): 91 A1 B1 + Codes of length 09 bits (005 total): 20 30 C1 D1 F1 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F0 + Codes of length 12 bits (001 total): 40 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008CA0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000EDFD + + +*** Searching Compression Signatures *** + + Signature: 01B8FDD60747E53114DC15797CC09B4E + Signature (Rotated): 011975EE86201F10E48E4F365C73A839 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [071 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [071 ] + SW :[IrfanView ] [071 ] + SW :[idImager ] [071 ] + SW :[FastStone Image Viewer ] [071 ] + SW :[NeatImage ] [071 ] + SW :[Paint.NET ] [071 ] + SW :[Photomatix ] [071 ] + SW :[XnView ] [071 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt new file mode 100644 index 0000000000..af39df365c --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt @@ -0,0 +1,471 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue178-BadCoeffsProgressive-Lemon.jpg] + Filesize: [279270] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 2 2 1 + DQT, Row #4: 1 1 1 1 1 2 2 2 + DQT, Row #5: 1 1 1 1 2 2 2 2 + DQT, Row #6: 1 1 2 2 2 2 2 2 + DQT, Row #7: 1 2 2 2 2 2 2 2 + Approx quality factor = 98.32 (scaling=3.35 variance=5.00) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 2 2 2 2 + DQT, Row #1: 1 1 1 1 2 2 2 2 + DQT, Row #2: 1 1 1 2 2 2 2 2 + DQT, Row #3: 1 1 2 2 2 2 2 2 + DQT, Row #4: 2 2 2 2 2 2 2 2 + DQT, Row #5: 2 2 2 2 2 2 2 2 + DQT, Row #6: 2 2 2 2 2 2 2 2 + DQT, Row #7: 2 2 2 2 2 2 2 2 + Approx quality factor = 98.83 (scaling=2.34 variance=0.89) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 710 + Samples per Line = 710 + Image Size = 710 x 710 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 30 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 05 + Codes of length 03 bits (004 total): 03 04 06 07 + Codes of length 04 bits (003 total): 00 02 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D1 + Huffman table length = 29 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (005 total): 00 01 02 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000F0 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002D06 + Huffman table length = 49 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 02 + Codes of length 03 bits (004 total): 00 01 03 04 + Codes of length 04 bits (002 total): 05 11 + Codes of length 05 bits (002 total): 06 12 + Codes of length 06 bits (002 total): 13 21 + Codes of length 07 bits (002 total): 07 14 + Codes of length 08 bits (001 total): 22 + Codes of length 09 bits (003 total): 10 15 31 + Codes of length 10 bits (004 total): 16 23 32 41 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (004 total): 08 30 33 50 + Codes of length 13 bits (003 total): 24 40 42 + Codes of length 14 bits (001 total): 34 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 030 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002D39 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007ADB + Huffman table length = 72 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (005 total): 05 22 41 51 61 + Codes of length 07 bits (005 total): 06 13 71 81 A1 + Codes of length 08 bits (005 total): 14 32 91 B1 F0 + Codes of length 09 bits (006 total): 23 42 52 C1 D1 E1 + Codes of length 10 bits (004 total): 10 15 33 62 + Codes of length 11 bits (003 total): 07 82 F1 + Codes of length 12 bits (006 total): 20 24 30 43 72 A2 + Codes of length 13 bits (006 total): 16 34 53 92 B2 E2 + Codes of length 14 bits (003 total): 25 44 93 + Codes of length 15 bits (001 total): D2 + Codes of length 16 bits (000 total): + Total number of codes: 053 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007B25 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000A7E3 + Huffman table length = 74 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (005 total): 05 12 21 31 41 + Codes of length 06 bits (005 total): 06 13 22 51 61 + Codes of length 07 bits (004 total): 32 71 81 91 + Codes of length 08 bits (006 total): 14 42 52 A1 B1 F0 + Codes of length 09 bits (008 total): 07 10 15 23 62 C1 D1 E1 + Codes of length 10 bits (004 total): 33 43 72 92 + Codes of length 11 bits (004 total): 24 82 A2 F1 + Codes of length 12 bits (004 total): 16 34 63 D2 + Codes of length 13 bits (006 total): 20 40 53 B2 C2 E2 + Codes of length 14 bits (003 total): 17 25 30 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 055 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000A82F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000E96D + Huffman table length = 84 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (003 total): 00 03 21 + Codes of length 05 bits (005 total): 04 12 31 41 51 + Codes of length 06 bits (004 total): 05 22 61 71 + Codes of length 07 bits (006 total): 13 32 81 91 A1 F0 + Codes of length 08 bits (008 total): 10 14 23 42 52 B1 C1 D1 + Codes of length 09 bits (003 total): 33 62 E1 + Codes of length 10 bits (005 total): 06 72 82 92 F1 + Codes of length 11 bits (006 total): 15 20 24 43 53 A2 + Codes of length 12 bits (004 total): 30 34 63 73 + Codes of length 13 bits (004 total): 44 83 B2 C2 + Codes of length 14 bits (005 total): 40 50 93 A3 D2 + Codes of length 15 bits (002 total): 16 25 + Codes of length 16 bits (007 total): 26 35 54 60 64 B3 E2 + Total number of codes: 065 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000E9C3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001AD55 + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 00 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (002 total): 61 71 + Codes of length 07 bits (002 total): 81 91 + Codes of length 08 bits (002 total): A1 B1 + Codes of length 09 bits (003 total): C1 D1 F0 + Codes of length 10 bits (000 total): + Codes of length 11 bits (003 total): 10 E1 F1 + Codes of length 12 bits (001 total): 20 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001AD7F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000287B1 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00028DB3 + Huffman table length = 39 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 00 31 + Codes of length 05 bits (001 total): 41 + Codes of length 06 bits (003 total): 51 61 71 + Codes of length 07 bits (003 total): 81 91 F0 + Codes of length 08 bits (005 total): A1 B1 C1 D1 E1 + Codes of length 09 bits (001 total): F1 + Codes of length 10 bits (001 total): 10 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00028DDC + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0002CD0C + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 00 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (004 total): 71 81 91 F0 + Codes of length 08 bits (002 total): A1 B1 + Codes of length 09 bits (003 total): C1 D1 E1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): 30 + Codes of length 12 bits (001 total): 10 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0002CD37 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00031187 + Huffman table length = 38 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (001 total): 21 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 00 31 41 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 51 61 + Codes of length 08 bits (002 total): 71 81 + Codes of length 09 bits (002 total): 91 A1 + Codes of length 10 bits (002 total): B1 C1 + Codes of length 11 bits (003 total): D1 E1 F0 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 10 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000311AF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000442E4 + + +*** Searching Compression Signatures *** + + Signature: 01C7F83908166C226C06A44017421732 + Signature (Rotated): 01D3EFDD3855C42AE3E0E6289F1A6726 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Canon ] [Canon EOS-1Ds Mark II ] [fine ] No + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[NIKON ] [NIKON D2X ] [FINE ] No + CAM:[NIKON ] [NIKON D3 ] [FINE ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-R1 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Digital Photo Professiona] [09 ] + SW :[IJG Library ] [099 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [099 ] + SW :[IrfanView ] [099 ] + SW :[idImager ] [099 ] + SW :[FastStone Image Viewer ] [099 ] + SW :[NeatImage ] [099 ] + SW :[Paint.NET ] [099 ] + SW :[Photomatix ] [099 ] + SW :[XnView ] [099 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt new file mode 100644 index 0000000000..f5b6d277d7 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt @@ -0,0 +1,94 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue214-CriticalEOF .jpg] + Filesize: [35601] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 39251 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0015 + [Make ] = "NIKON CORPORATION" + [Model ] = "NIKON D40" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Ver.1.10 " + [DateTime ] = "2009:02:17 08:30:16" + [YCbCrPositioning ] = Co-sited + [ExifOffset ] = @ 0x015C + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + Offset to Next IFD = 0x00007652 + + EXIF IFD1 @ Absolute 0x00007670 + Dir Length = 0x0007 + [Compression ] = JPEG + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x76BC = @ 0x76DA + [JpegIFByteCount ] = 0x[0000228F] / 8847 + [YCbCrPositioning ] = Co-sited + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x0000017A + Dir Length = 0x001C + [ExposureTime ] = 10/1250 s + [FNumber ] = F5.6 + [ExposureProgram ] = Not defined + [ISOSpeedRatings ] = 220 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2009:02:17 08:30:16" + [DateTimeDigitized ] = "2009:02:17 08:30:15" + [ComponentsConfiguration ] = [Y Cb Cr .] + [CompressedBitsPerPixel ] = 1/1 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 41/10 + [MeteringMode ] = Pattern + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 30 mm + [MakerNote ] = @ 0x030A + [UserComment ] = " " + [SubSecTime ] = "60" + [SubSecTimeOriginal ] = "60" + [SubSecTimeDigitized ] = "60" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 3008 + [ExifImageHeight ] = 2000 + [SensingMethod ] = One-chip color area sensor + [FileSource ] = DSC + [SceneType ] = A directly photographed image + [CFAPattern ] = + = [ Blu Grn ] + = [ Grn Red ] + + EXIF MakerIFD @ Absolute 0x00000328 + Makernote decode option not enabled. + +ERROR: Early EOF - file may be missing EOI diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt new file mode 100644 index 0000000000..1f98e67dc1 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt @@ -0,0 +1,468 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue385-BadZigZag-Progressive.jpg] + Filesize: [388517] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 1440 + Samples per Line = 1920 + Image Size = 1920 x 1440 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CF + Huffman table length = 25 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000EA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007E0B + Huffman table length = 55 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (003 total): 04 12 21 + Codes of length 06 bits (002 total): 05 10 + Codes of length 07 bits (004 total): 13 20 22 31 + Codes of length 08 bits (004 total): 06 14 30 41 + Codes of length 09 bits (005 total): 15 32 33 34 40 + Codes of length 10 bits (005 total): 23 24 35 42 50 + Codes of length 11 bits (000 total): + Codes of length 12 bits (002 total): 25 70 + Codes of length 13 bits (003 total): 16 44 60 + Codes of length 14 bits (001 total): 36 + Codes of length 15 bits (001 total): 45 + Codes of length 16 bits (001 total): 43 + Total number of codes: 036 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007E44 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00012C0C + Huffman table length = 46 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (004 total): 02 10 12 20 + Codes of length 05 bits (000 total): + Codes of length 06 bits (004 total): 03 21 30 31 + Codes of length 07 bits (006 total): 13 32 40 41 50 51 + Codes of length 08 bits (002 total): 22 61 + Codes of length 09 bits (002 total): 04 60 + Codes of length 10 bits (003 total): 23 33 71 + Codes of length 11 bits (001 total): 42 + Codes of length 12 bits (001 total): 05 + Codes of length 13 bits (001 total): 43 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 027 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00012C3C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00013C45 + Huffman table length = 43 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (004 total): 02 10 12 20 + Codes of length 05 bits (001 total): 30 + Codes of length 06 bits (004 total): 03 21 31 40 + Codes of length 07 bits (002 total): 41 50 + Codes of length 08 bits (002 total): 13 51 + Codes of length 09 bits (002 total): 22 60 + Codes of length 10 bits (003 total): 32 42 61 + Codes of length 11 bits (001 total): 04 + Codes of length 12 bits (001 total): 81 + Codes of length 13 bits (001 total): 71 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00013C72 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000148F2 + Huffman table length = 75 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (000 total): + Codes of length 04 bits (004 total): 02 11 21 31 + Codes of length 05 bits (002 total): 03 10 + Codes of length 06 bits (006 total): 12 20 22 32 41 51 + Codes of length 07 bits (007 total): 04 30 33 61 71 81 91 + Codes of length 08 bits (005 total): 13 40 50 52 72 + Codes of length 09 bits (007 total): 23 34 42 62 82 92 A1 + Codes of length 10 bits (001 total): B1 + Codes of length 11 bits (006 total): 14 60 70 73 C1 E1 + Codes of length 12 bits (005 total): 05 63 83 A2 D1 + Codes of length 13 bits (004 total): 24 43 53 93 + Codes of length 14 bits (002 total): 74 F0 + Codes of length 15 bits (002 total): 15 B2 + Codes of length 16 bits (003 total): 35 E2 F1 + Total number of codes: 056 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001493F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001BD13 + Huffman table length = 44 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (002 total): 10 61 + Codes of length 07 bits (001 total): 71 + Codes of length 08 bits (004 total): 20 81 91 A1 + Codes of length 09 bits (002 total): 30 B1 + Codes of length 10 bits (002 total): C1 F0 + Codes of length 11 bits (003 total): 40 D1 F1 + Codes of length 12 bits (001 total): E1 + Codes of length 13 bits (001 total): 50 + Codes of length 14 bits (001 total): 60 + Codes of length 15 bits (001 total): 70 + Codes of length 16 bits (000 total): + Total number of codes: 025 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001BD41 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0002C20D + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0002E1DF + Huffman table length = 37 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (002 total): 10 41 + Codes of length 07 bits (003 total): 20 51 61 + Codes of length 08 bits (001 total): 71 + Codes of length 09 bits (001 total): 30 + Codes of length 10 bits (001 total): 81 + Codes of length 11 bits (001 total): 40 + Codes of length 12 bits (001 total): 91 + Codes of length 13 bits (001 total): A1 + Codes of length 14 bits (001 total): B1 + Codes of length 15 bits (001 total): C1 + Codes of length 16 bits (000 total): + Total number of codes: 018 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0002E206 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000313D7 + Huffman table length = 36 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 21 31 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 20 41 51 + Codes of length 07 bits (001 total): 61 + Codes of length 08 bits (001 total): 71 + Codes of length 09 bits (001 total): 30 + Codes of length 10 bits (001 total): 81 + Codes of length 11 bits (001 total): 40 + Codes of length 12 bits (001 total): 91 + Codes of length 13 bits (001 total): B1 + Codes of length 14 bits (001 total): A1 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 017 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000313FD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00033E31 + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (002 total): 61 71 + Codes of length 07 bits (002 total): 81 91 + Codes of length 08 bits (002 total): A1 B1 + Codes of length 09 bits (003 total): 10 C1 D1 + Codes of length 10 bits (001 total): F0 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (001 total): 30 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00033E5B + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0005EDA3 + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt new file mode 100644 index 0000000000..22e9a99dd2 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt @@ -0,0 +1,438 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue394-MultiHuffmanBaseline-Speakers.jpg] + Filesize: [257401] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000002 + Length = 576 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 560 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1999-06-03 00:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'none' (0x6E6F6E65) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000244 + Length = 90 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x003D] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 3 + IPTC [002:055] Date Created = "20161215" + IPTC [002:060] Time Created = "043026-0600" + IPTC [002:221] ? = ??? + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000002A0 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00000326 + Length = 4 + interval = 115 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0000032C + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF1 (Extended Sequential DCT, Huffman) (xFFC1) *** + OFFSET: 0x0000033C + Frame header length = 17 + Precision = 8 + Number of Lines = 496 + Samples per Line = 920 + Image Size = 920 x 496 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000034F + Huffman table length = 626 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 05 + Codes of length 03 bits (005 total): 02 03 04 06 07 + Codes of length 04 bits (001 total): 01 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 00 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 09 0A 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 01 04 05 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 07 08 + Codes of length 08 bits (003 total): 09 0A 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 2 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (003 total): 00 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (000 total): + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (005 total): 07 08 09 0A 0B + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 03 11 + Codes of length 04 bits (002 total): 04 12 + Codes of length 05 bits (001 total): 21 + Codes of length 06 bits (003 total): 00 05 13 + Codes of length 07 bits (002 total): 22 31 + Codes of length 08 bits (004 total): 06 14 32 41 + Codes of length 09 bits (002 total): 23 51 + Codes of length 10 bits (003 total): 15 42 61 + Codes of length 11 bits (005 total): 07 16 33 52 71 + Codes of length 12 bits (006 total): 24 43 62 81 91 F0 + Codes of length 13 bits (006 total): 25 34 72 A1 B1 C1 + Codes of length 14 bits (012 total): 08 18 26 46 53 63 82 92 93 D1 D2 F1 + Codes of length 15 bits (111 total): 09 0A 17 19 1A 27 28 29 2A 35 36 37 38 39 3A 44 + 45 47 48 49 4A 54 55 56 57 58 59 5A 64 65 66 67 + 68 69 6A 73 74 75 76 77 78 79 7A 83 84 85 86 87 + 88 89 8A 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7 + A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 + C6 C7 C8 C9 CA D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 + E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 F7 F8 F9 + Codes of length 16 bits (001 total): FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (003 total): 02 21 31 + Codes of length 05 bits (004 total): 41 51 61 F0 + Codes of length 06 bits (006 total): 03 12 13 71 81 91 + Codes of length 07 bits (006 total): 14 A1 B1 C1 D1 E1 + Codes of length 08 bits (002 total): 04 F1 + Codes of length 09 bits (002 total): 22 32 + Codes of length 10 bits (002 total): 52 62 + Codes of length 11 bits (004 total): 05 42 72 A2 + Codes of length 12 bits (125 total): 06 07 08 09 0A 15 16 17 18 19 1A 23 24 25 26 27 + 28 29 2A 33 34 35 36 37 38 39 3A 43 44 45 46 47 + 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 + 68 69 6A 73 74 75 76 77 78 79 7A 82 83 84 85 86 + 87 88 89 8A 92 93 94 95 96 97 98 99 9A A3 A4 A5 + A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 + C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA + E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 + Codes of length 13 bits (005 total): F6 F7 F8 F9 FA + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 162 + + ---- + Destination ID = 2 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 02 + Codes of length 05 bits (005 total): 12 21 31 41 51 + Codes of length 06 bits (004 total): 03 61 71 F0 + Codes of length 07 bits (004 total): 13 81 91 A1 + Codes of length 08 bits (006 total): 04 14 C1 D1 E1 F1 + Codes of length 09 bits (002 total): 22 B1 + Codes of length 10 bits (001 total): 42 + Codes of length 11 bits (004 total): 32 52 92 D2 + Codes of length 12 bits (131 total): 05 06 07 08 09 0A 15 16 17 18 19 1A 23 24 25 26 + 27 28 29 2A 33 34 35 36 37 38 39 3A 43 44 45 46 + 47 48 49 4A 53 54 55 56 57 58 59 5A 62 63 64 65 + 66 67 68 69 6A 72 73 74 75 76 77 78 79 7A 82 83 + 84 85 86 87 88 89 8A 93 94 95 96 97 98 99 9A A2 + A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 + BA C2 C3 C4 C5 C6 C7 C8 C9 CA D3 D4 D5 D6 D7 D8 + D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 + F7 F8 F9 + Codes of length 13 bits (001 total): FA + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000005C3 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=2(DC),2(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000005D1 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0003ED77.0 + + Compression stats: + Compression Ratio: 5.35:1 + Bits per pixel: 4.49:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1109 ( 16%) + # codes of length 03 bits: 4934 ( 69%) + # codes of length 04 bits: 705 ( 10%) + # codes of length 05 bits: 22 ( 0%) + # codes of length 06 bits: 360 ( 5%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2599 ( 36%) + # codes of length 03 bits: 2938 ( 41%) + # codes of length 04 bits: 1592 ( 22%) + # codes of length 05 bits: 1 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 2, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 3838 ( 54%) + # codes of length 03 bits: 3132 ( 44%) + # codes of length 04 bits: 156 ( 2%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 4 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 170962 ( 54%) + # codes of length 03 bits: 67518 ( 21%) + # codes of length 04 bits: 33616 ( 11%) + # codes of length 05 bits: 9306 ( 3%) + # codes of length 06 bits: 15458 ( 5%) + # codes of length 07 bits: 7462 ( 2%) + # codes of length 08 bits: 6393 ( 2%) + # codes of length 09 bits: 1640 ( 1%) + # codes of length 10 bits: 1220 ( 0%) + # codes of length 11 bits: 975 ( 0%) + # codes of length 12 bits: 581 ( 0%) + # codes of length 13 bits: 213 ( 0%) + # codes of length 14 bits: 134 ( 0%) + # codes of length 15 bits: 75 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 11236 ( 26%) + # codes of length 03 bits: 12123 ( 28%) + # codes of length 04 bits: 7424 ( 17%) + # codes of length 05 bits: 5864 ( 13%) + # codes of length 06 bits: 4420 ( 10%) + # codes of length 07 bits: 1997 ( 5%) + # codes of length 08 bits: 545 ( 1%) + # codes of length 09 bits: 244 ( 1%) + # codes of length 10 bits: 61 ( 0%) + # codes of length 11 bits: 41 ( 0%) + # codes of length 12 bits: 31 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 2, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 15434 ( 46%) + # codes of length 03 bits: 3540 ( 11%) + # codes of length 04 bits: 2524 ( 8%) + # codes of length 05 bits: 5638 ( 17%) + # codes of length 06 bits: 3224 ( 10%) + # codes of length 07 bits: 1556 ( 5%) + # codes of length 08 bits: 1170 ( 3%) + # codes of length 09 bits: 277 ( 1%) + # codes of length 10 bits: 14 ( 0%) + # codes of length 11 bits: 111 ( 0%) + # codes of length 12 bits: 34 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 97] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 762, 70, -70] RGB=[210,226,237] @ MCU[ 56, 4] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 61 + Next position in scan buffer: Offset 0x0003ED76.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0003ED77 + + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt new file mode 100644 index 0000000000..47e77a4f41 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt @@ -0,0 +1,406 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue517-No-EOI-Progressive.jpg] + Filesize: [2192567] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 500 x 500 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 248 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 500/1 + [YResolution ] = 500/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CS6 (Macintosh)" + [DateTime ] = "2018:01:06 12:59:23" + [ExifOffset ] = @ 0x00A6 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000C4 + Dir Length = 0x0004 + [DateTimeDigitized ] = "2018:01:06 04:40:19" + [ColorSpace ] = sRGB + [ExifImageWidth ] = 0x[000008CA] / 2250 + [ExifImageHeight ] = 0x[000008CA] / 2250 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x0000010E + Length = 4875 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x0000141B + Length = 100 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x002C] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 2 + IPTC [002:062] Digital Creation Date = "20180106" + IPTC [002:063] Digital Creation Time = "044019-0500" + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x5D 51 F3 F0 D0 DE FC 5F 94 67 16 6F B1 02 A3 89 | ]Q....._.g.o.... + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x00001481 + Frame header length = 17 + Precision = 8 + Number of Lines = 2250 + Samples per Line = 2250 + Image Size = 2250 x 2250 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001494 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (005 total): 02 04 01 05 00 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000014B5 + Huffman table length = 195 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 00 03 + Codes of length 04 bits (003 total): 11 04 12 + Codes of length 05 bits (002 total): 21 05 + Codes of length 06 bits (004 total): 31 13 22 10 + Codes of length 07 bits (003 total): 06 41 51 + Codes of length 08 bits (004 total): 32 14 61 71 + Codes of length 09 bits (006 total): 23 07 81 20 91 42 + Codes of length 10 bits (004 total): 15 A1 52 33 + Codes of length 11 bits (007 total): B1 24 62 30 16 C1 72 + Codes of length 12 bits (006 total): D1 43 92 34 82 08 + Codes of length 13 bits (004 total): E1 53 40 25 + Codes of length 14 bits (008 total): 63 17 35 F0 93 73 A2 50 + Codes of length 15 bits (006 total): 44 B2 83 F1 26 54 + Codes of length 16 bits (115 total): 36 64 94 74 C2 60 D2 84 A3 18 70 E2 27 45 37 65 + B3 55 75 A4 95 C3 85 F2 D3 46 76 80 E3 47 56 66 + B4 09 0A 19 1A 28 29 2A 38 39 3A 48 49 4A 57 58 + 59 5A 67 68 69 6A 77 78 79 7A 86 87 88 89 8A 90 + 96 97 98 99 9A A0 A5 A6 A7 A8 A9 AA B0 B5 B6 B7 + B8 B9 BA C0 C4 C5 C6 C7 C8 C9 CA D0 D4 D5 D6 D7 + D8 D9 DA E0 E4 E5 E6 E7 E8 E9 EA F3 F4 F5 F6 F7 + F8 F9 FA + Total number of codes: 176 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000157A + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 01 02 00 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000159B + Huffman table length = 195 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (003 total): 10 12 21 + Codes of length 06 bits (003 total): 04 20 31 + Codes of length 07 bits (003 total): 41 13 05 + Codes of length 08 bits (002 total): 30 22 + Codes of length 09 bits (003 total): 32 51 14 + Codes of length 10 bits (005 total): 40 06 33 23 61 + Codes of length 11 bits (002 total): 42 15 + Codes of length 12 bits (005 total): 71 52 34 81 50 + Codes of length 13 bits (002 total): 24 91 + Codes of length 14 bits (004 total): A1 43 B1 16 + Codes of length 15 bits (004 total): 07 62 35 53 + Codes of length 16 bits (135 total): F0 D1 25 60 C1 44 E1 72 F1 17 82 63 36 70 26 45 + 54 92 27 A2 D2 08 09 0A 18 19 1A 28 29 2A 37 38 + 39 3A 46 47 48 49 4A 55 56 57 58 59 5A 64 65 66 + 67 68 69 6A 73 74 75 76 77 78 79 7A 80 83 84 85 + 86 87 88 89 8A 90 93 94 95 96 97 98 99 9A A0 A3 + A4 A5 A6 A7 A8 A9 AA B0 B2 B3 B4 B5 B6 B7 B8 B9 + BA C0 C2 C3 C4 C5 C6 C7 C8 C9 CA D0 D3 D4 D5 D6 + D7 D8 D9 DA E0 E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 176 + + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00001660 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 2 + DQT, Row #1: 1 1 1 1 1 1 1 2 + DQT, Row #2: 1 1 1 1 1 1 2 2 + DQT, Row #3: 1 1 1 1 1 2 2 3 + DQT, Row #4: 1 1 1 1 2 2 3 3 + DQT, Row #5: 1 1 1 2 2 3 3 3 + DQT, Row #6: 1 1 2 2 3 3 3 3 + DQT, Row #7: 2 2 2 3 3 3 3 3 + Approx quality factor = 98.11 (scaling=3.79 variance=4.10) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000016A5 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 2 3 3 3 3 + DQT, Row #1: 1 1 1 2 3 3 3 3 + DQT, Row #2: 1 1 2 3 3 3 3 3 + DQT, Row #3: 2 2 3 3 3 3 3 3 + DQT, Row #4: 3 3 3 3 3 3 3 3 + DQT, Row #5: 3 3 3 3 3 3 3 3 + DQT, Row #6: 3 3 3 3 3 3 3 3 + DQT, Row #7: 3 3 3 3 3 3 3 3 + Approx quality factor = 98.36 (scaling=3.29 variance=0.42) + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000016EA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00023AAF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0003E82C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0006B107 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0008AA32 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000BA727 + Huffman table length = 51 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 11 00 21 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (002 total): 71 81 + Codes of length 08 bits (002 total): 91 A1 + Codes of length 09 bits (002 total): B1 C1 + Codes of length 10 bits (003 total): F0 D1 10 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (002 total): 20 30 + Codes of length 16 bits (011 total): 40 50 60 70 80 90 A0 B0 C0 D0 E0 + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000BA75C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000FE1E7 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001056B6 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 21 31 10 + Codes of length 06 bits (000 total): + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (002 total): 51 61 + Codes of length 09 bits (005 total): 20 71 F0 91 81 + Codes of length 10 bits (005 total): A1 B1 D1 C1 E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (001 total): 50 + Codes of length 16 bits (009 total): 60 70 80 90 A0 B0 C0 D0 E0 + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001056EB + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0014E060 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001879C8 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x002174B5 + + +*** Searching Compression Signatures *** + + Signature: 01DADDC4908E9BA57CC067EEAD54E67D + Signature (Rotated): 01DADDC4908E9BA57CC067EEAD54E67D + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CS6 (Macintosh)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 12 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt new file mode 100644 index 0000000000..1b1027f273 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt @@ -0,0 +1,759 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue518-Bad-RST-Progressive.jpg] + Filesize: [3764739] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 14215 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0009 + [Make ] = "OLYMPUS CORPORATION" + [Model ] = "E-1" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "GIMP 2.8.10" + [DateTime ] = "2017:04:18 16:37:56" + [ExifOffset ] = @ 0x00BE + Offset to Next IFD = 0x000001DC + + EXIF IFD1 @ Absolute 0x000001FA + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x023A = @ 0x0258 + [JpegIFByteCount ] = 0x[00003545] / 13637 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000DC + Dir Length = 0x0011 + [ExposureTime ] = 1/4 s + [FNumber ] = F18.0 + [ExposureProgram ] = Manual + [ISOSpeedRatings ] = 100 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2005:07:20 20:08:42" + [ShutterSpeedValue ] = 2/1 + [ApertureValue ] = 833985/100000 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 2972656/1000000 + [MeteringMode ] = CenterWeightedAverage + [Flash ] = Flash did not fire + [FocalLength ] = 14 mm + [FlashPixVersion ] = 01.00 + [ColorSpace ] = Uncalibrated + [ExifImageWidth ] = 0x[00000BB8] / 3000 + [ExifImageHeight ] = 0x[00000BB8] / 3000 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x0000379D + Comment length = 3 + Comment= + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000037A2 + Length = 5091 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + | + | + | + | 3.1 + | _7201666.ORF + | Custom + | 7450 + | -7 + | -0.75 + | True + | 4 + | True + | 100 + | True + | 0 + | 0 + | 25 + | 0 + | 25 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | Medium Contrast + | ACR 2.4 + | True + | False + | True + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | 3.1 + | _7201666.ORF + | Custom + | 7450 + | -7 + | -0.75 + | True + | 4 + | True + | 100 + | True + | 0 + | 0 + | 25 + | 0 + | 25 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | Medium Contrast + | ACR 2.4 + | True + | False + | True + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | + | + | 0 + | Adobe Photoshop CS6 (Macintosh) + | 0 + | 2014-06-09T12:43:59-04:00 + | 2005-07-21T18:39:06-06:00 + | 2014-06-09T12:43:59-04:00 + | + | + | xmp.iid:0A801174072068118083C9374AAA53C2 + | uuid:021303F2FBA711D98B5DCD54C315AFD0 + | + | xmp.iid:0A801174072068118083C9374AAA53C2 + | uuid:021303F2FBA711D98B5DCD54C315AFD0 + | + | + | + | + | + | + | + | + | image/jpeg + | + | + | 2005-07-20T20:08:42 + | A8D68AA81537D1C7170A5C69A46C6C94 + | 3 + | Adobe RGB (1998) + | + | + | 100 + | + | + | + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00004B87 + Length = 3160 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3144 bytes + Preferred CMM Type : 'Lino' (0x4C696E6F) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1998-02-09 06:49:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Microsoft Corporation ('MSFT' (0x4D534654)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'IEC ' (0x49454320) + Device Model : 'sRGB' (0x73524742) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'HP ' (0x48502020) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000057E1 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00005826 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000586B + Frame header length = 17 + Precision = 8 + Number of Lines = 3000 + Samples per Line = 3000 + Image Size = 3000 x 3000 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000587E + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 04 05 + Codes of length 03 bits (002 total): 03 06 + Codes of length 04 bits (003 total): 00 01 02 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000589C + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 01 02 03 + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x000058B9 + Length = 4 + interval = 375 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000058BF + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0004A3DA + Huffman table length = 55 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 01 04 05 + Codes of length 04 bits (000 total): + Codes of length 05 bits (001 total): 00 + Codes of length 06 bits (004 total): 06 11 12 13 + Codes of length 07 bits (001 total): 14 + Codes of length 08 bits (003 total): 15 21 22 + Codes of length 09 bits (003 total): 10 23 31 + Codes of length 10 bits (004 total): 07 20 24 41 + Codes of length 11 bits (002 total): 16 32 + Codes of length 12 bits (002 total): 30 33 + Codes of length 13 bits (002 total): 25 40 + Codes of length 14 bits (002 total): 17 42 + Codes of length 15 bits (000 total): + Codes of length 16 bits (007 total): 34 50 60 43 26 35 44 + Total number of codes: 036 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0004A413 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000B0746 + Huffman table length = 62 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (004 total): 03 10 12 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (004 total): 13 20 22 51 + Codes of length 08 bits (002 total): 04 32 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (003 total): 14 30 71 + Codes of length 11 bits (003 total): 23 40 42 + Codes of length 12 bits (003 total): 33 50 52 + Codes of length 13 bits (003 total): 05 81 91 + Codes of length 14 bits (003 total): 60 A1 B1 + Codes of length 15 bits (000 total): + Codes of length 16 bits (011 total): 15 24 62 43 53 C1 D1 72 F0 F1 E1 + Total number of codes: 043 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000B0786 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000E3DFE + Huffman table length = 69 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (002 total): 03 21 + Codes of length 05 bits (002 total): 12 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (006 total): 04 10 13 22 41 51 + Codes of length 08 bits (001 total): 32 + Codes of length 09 bits (002 total): 20 61 + Codes of length 10 bits (005 total): 05 14 23 42 71 + Codes of length 11 bits (002 total): 30 52 + Codes of length 12 bits (004 total): 33 40 81 91 + Codes of length 13 bits (005 total): 15 50 60 A1 B1 + Codes of length 14 bits (002 total): 62 F0 + Codes of length 15 bits (000 total): + Codes of length 16 bits (015 total): 24 43 70 C1 D1 06 53 72 E1 F1 25 34 44 63 A2 + Total number of codes: 050 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000E3E45 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0012926F + Huffman table length = 79 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (002 total): 11 12 + Codes of length 05 bits (005 total): 04 13 21 31 41 + Codes of length 06 bits (003 total): 22 32 51 + Codes of length 07 bits (003 total): 23 42 61 + Codes of length 08 bits (002 total): 05 14 + Codes of length 09 bits (003 total): 33 52 71 + Codes of length 10 bits (007 total): 10 24 43 62 81 91 A1 + Codes of length 11 bits (001 total): B1 + Codes of length 12 bits (006 total): 15 20 30 53 72 C1 + Codes of length 13 bits (004 total): 34 40 50 82 + Codes of length 14 bits (003 total): 60 63 92 + Codes of length 15 bits (002 total): A2 D1 + Codes of length 16 bits (015 total): 25 44 70 E1 F0 73 83 B2 F1 06 54 16 35 C2 74 + Total number of codes: 060 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001292C0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001CCECE + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (003 total): 41 51 61 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 71 81 + Codes of length 08 bits (002 total): 91 A1 + Codes of length 09 bits (002 total): 10 B1 + Codes of length 10 bits (002 total): C1 D1 + Codes of length 11 bits (003 total): 20 E1 F0 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (001 total): 50 + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001CCEFA + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0024E532 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0025B81A + Huffman table length = 42 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (000 total): + Codes of length 08 bits (002 total): 10 51 + Codes of length 09 bits (002 total): 61 71 + Codes of length 10 bits (001 total): 81 + Codes of length 11 bits (003 total): 20 91 A1 + Codes of length 12 bits (005 total): 30 B1 C1 D1 F0 + Codes of length 13 bits (001 total): E1 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (001 total): F1 + Codes of length 16 bits (001 total): 50 + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0025B846 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0029943F + Huffman table length = 43 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 41 51 + Codes of length 08 bits (002 total): 10 61 + Codes of length 09 bits (001 total): 71 + Codes of length 10 bits (003 total): 81 91 A1 + Codes of length 11 bits (005 total): 20 B1 C1 D1 F0 + Codes of length 12 bits (001 total): E1 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (001 total): F1 + Codes of length 15 bits (000 total): + Codes of length 16 bits (003 total): 40 50 60 + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0029946C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x002E23F1 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (003 total): 41 51 61 + Codes of length 06 bits (001 total): 71 + Codes of length 07 bits (000 total): + Codes of length 08 bits (002 total): 81 91 + Codes of length 09 bits (002 total): A1 B1 + Codes of length 10 bits (002 total): C1 D1 + Codes of length 11 bits (003 total): 10 E1 F0 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (001 total): 30 + Codes of length 15 bits (001 total): 40 + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x002E241C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00397201 + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000258 + Length: 0x00003545 (13637) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: APP0 + Length = 16 + + * Embedded Thumb Marker: DQT + Length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + + * Embedded Thumb Marker: DQT + Length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 196 + Samples per Line = 196 + Image Size = 196 x 196 + + * Embedded Thumb Marker: DHT + Length = 31 + + * Embedded Thumb Marker: DHT + Length = 181 + + * Embedded Thumb Marker: DHT + Length = 31 + + * Embedded Thumb Marker: DHT + Length = 181 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 13024 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [OLYMPUS CORPORATION] [E-1] + EXIF Makernotes: NONE + EXIF Software: OK [GIMP 2.8.10] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] No + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt new file mode 100644 index 0000000000..aadf150e6d --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt @@ -0,0 +1,364 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue520-InvalidCast.jpg] + Filesize: [7751] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 499 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0011 + [DateTime ] = "2017:09:06 15:13:32" + [Model ] = "SAMSUNG-SM-J320AZ" + [Orientation ] = 1 = Row 0: top, Col 0: left + [WhiteBalance ] = Auto white balance + [DateTime ] = "2017:09:06 15:13:04" + [Make ] = "samsung" + [GPSOffset ] = @ 0x0124 + [ExifOffset ] = @ 0x01CD + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000001EB + Dir Length = 0x0002 + + EXIF GPSIFD @ Absolute 0x00000142 + Dir Length = 0x0008 + [GPSTimeStamp ] = 115:8:12.00 + [GPSLatitudeRef ] = "N" + [GPSLongitude ] = 115 deg 8' 12.000" + [GPSLongitudeRef ] = "W" + [GPSDateStamp ] = "2017:08:08" + [GPSLatitude ] = 36 deg 11' 18.000" + [GPSAltitudeRef ] = Below Sea Level + [GPSAltitude ] = 0.000 m + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000209 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 2 2 1 + DQT, Row #4: 1 1 1 1 1 2 2 2 + DQT, Row #5: 1 1 1 1 2 2 2 2 + DQT, Row #6: 1 1 2 2 2 2 2 2 + DQT, Row #7: 1 2 2 2 2 2 2 2 + Approx quality factor = 98.32 (scaling=3.35 variance=5.00) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000024E + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 2 2 2 2 + DQT, Row #1: 1 1 1 1 2 2 2 2 + DQT, Row #2: 1 1 1 2 2 2 2 2 + DQT, Row #3: 1 1 2 2 2 2 2 2 + DQT, Row #4: 2 2 2 2 2 2 2 2 + DQT, Row #5: 2 2 2 2 2 2 2 2 + DQT, Row #6: 2 2 2 2 2 2 2 2 + DQT, Row #7: 2 2 2 2 2 2 2 2 + Approx quality factor = 98.83 (scaling=2.34 variance=0.89) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000293 + Frame header length = 17 + Precision = 8 + Number of Lines = 100 + Samples per Line = 100 + Image Size = 100 x 100 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002A6 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 0A + Codes of length 03 bits (001 total): 09 + Codes of length 04 bits (004 total): 06 07 08 0B + Codes of length 05 bits (003 total): 03 04 05 + Codes of length 06 bits (001 total): 01 + Codes of length 07 bits (001 total): 02 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002C7 + Huffman table length = 60 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (004 total): 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 00 07 11 + Codes of length 06 bits (003 total): 08 12 13 + Codes of length 07 bits (002 total): 14 21 + Codes of length 08 bits (003 total): 09 22 31 + Codes of length 09 bits (005 total): 0A 15 41 51 61 + Codes of length 10 bits (006 total): 16 23 24 32 33 71 + Codes of length 11 bits (003 total): 17 52 62 + Codes of length 12 bits (009 total): 18 42 54 73 91 93 A3 B1 B2 + Codes of length 13 bits (001 total): D2 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 041 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000305 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 03 04 05 06 07 + Codes of length 04 bits (001 total): 08 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 01 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000323 + Huffman table length = 50 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 04 05 11 + Codes of length 05 bits (003 total): 00 12 21 + Codes of length 06 bits (003 total): 06 22 31 + Codes of length 07 bits (003 total): 13 41 51 + Codes of length 08 bits (002 total): 61 71 + Codes of length 09 bits (004 total): 07 14 32 91 + Codes of length 10 bits (005 total): 15 23 42 81 D1 + Codes of length 11 bits (005 total): 16 62 92 A1 B1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000357 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000365 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00001E45.0 + + Compression stats: + Compression Ratio: 4.36:1 + Bits per pixel: 5.50:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 97 ( 49%) + # codes of length 03 bits: 25 ( 13%) + # codes of length 04 bits: 51 ( 26%) + # codes of length 05 bits: 18 ( 9%) + # codes of length 06 bits: 3 ( 2%) + # codes of length 07 bits: 2 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 26 ( 27%) + # codes of length 03 bits: 62 ( 63%) + # codes of length 04 bits: 5 ( 5%) + # codes of length 05 bits: 3 ( 3%) + # codes of length 06 bits: 2 ( 2%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 971 ( 16%) + # codes of length 03 bits: 3435 ( 57%) + # codes of length 04 bits: 456 ( 8%) + # codes of length 05 bits: 579 ( 10%) + # codes of length 06 bits: 285 ( 5%) + # codes of length 07 bits: 96 ( 2%) + # codes of length 08 bits: 74 ( 1%) + # codes of length 09 bits: 59 ( 1%) + # codes of length 10 bits: 30 ( 0%) + # codes of length 11 bits: 7 ( 0%) + # codes of length 12 bits: 9 ( 0%) + # codes of length 13 bits: 1 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1143 ( 50%) + # codes of length 03 bits: 254 ( 11%) + # codes of length 04 bits: 445 ( 19%) + # codes of length 05 bits: 228 ( 10%) + # codes of length 06 bits: 111 ( 5%) + # codes of length 07 bits: 48 ( 2%) + # codes of length 08 bits: 20 ( 1%) + # codes of length 09 bits: 22 ( 1%) + # codes of length 10 bits: 13 ( 1%) + # codes of length 11 bits: 5 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[193] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1001, -7, 97] RGB=[255,244,251] @ MCU[ 5, 3] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001E44.1 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00001E45 + + +*** Searching Compression Signatures *** + + Signature: 01C7F83908166C226C06A44017421732 + Signature (Rotated): 01D3EFDD3855C42AE3E0E6289F1A6726 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [samsung] [SAMSUNG-SM-J320AZ] + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Canon ] [Canon EOS-1Ds Mark II ] [fine ] No + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[NIKON ] [NIKON D2X ] [FINE ] No + CAM:[NIKON ] [NIKON D3 ] [FINE ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-R1 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Digital Photo Professiona] [09 ] + SW :[IJG Library ] [099 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [099 ] + SW :[IrfanView ] [099 ] + SW :[idImager ] [099 ] + SW :[FastStone Image Viewer ] [099 ] + SW :[NeatImage ] [099 ] + SW :[Paint.NET ] [099 ] + SW :[Photomatix ] [099 ] + SW :[XnView ] [099 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt new file mode 100644 index 0000000000..0ee1736d3c --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt @@ -0,0 +1,284 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue624-DhtHasWrongLength-Progressive-N.jpg] + Filesize: [30441] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 6 6 7 10 15 22 34 + DQT, Row #1: 6 7 8 11 14 16 21 30 + DQT, Row #2: 6 8 10 12 17 25 36 54 + DQT, Row #3: 7 11 12 16 21 30 42 62 + DQT, Row #4: 10 14 17 21 28 38 52 76 + DQT, Row #5: 15 16 25 30 38 50 68 95 + DQT, Row #6: 22 21 36 42 52 68 90 124 + DQT, Row #7: 34 30 54 62 76 95 124 167 + Approx quality factor = 71.19 (scaling=57.62 variance=593.35) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 6 6 6 7 10 15 22 34 + DQT, Row #1: 6 7 8 11 14 16 21 30 + DQT, Row #2: 6 8 10 12 17 25 36 54 + DQT, Row #3: 7 11 12 16 21 30 42 62 + DQT, Row #4: 10 14 17 21 28 38 52 76 + DQT, Row #5: 15 16 25 30 38 50 68 95 + DQT, Row #6: 22 21 36 42 52 68 90 124 + DQT, Row #7: 34 30 54 62 76 95 124 167 + Approx quality factor = 80.24 (scaling=39.51 variance=961.47) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009A + Frame header length = 17 + Precision = 8 + Number of Lines = 1080 + Samples per Line = 1080 + Image Size = 1080 x 1080 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000AD + Huffman table length = 51 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 05 06 + Codes of length 04 bits (003 total): 01 03 04 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 02 04 06 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000E2 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000151B + Huffman table length = 2 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000151F + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000022BA + Huffman table length = 2 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000022BE + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000309F + Huffman table length = 53 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 00 04 20 + Codes of length 05 bits (007 total): 11 31 33 34 50 71 72 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (005 total): 12 21 52 60 61 + Codes of length 08 bits (007 total): 10 13 22 32 41 51 A1 + Codes of length 09 bits (003 total): 23 53 62 + Codes of length 10 bits (005 total): 70 80 81 A0 F1 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 034 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000030D6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003353 + Huffman table length = 54 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 04 + Codes of length 04 bits (002 total): 03 05 + Codes of length 05 bits (008 total): 00 06 20 32 50 63 71 B1 + Codes of length 06 bits (005 total): 11 25 31 35 73 + Codes of length 07 bits (002 total): 12 21 + Codes of length 08 bits (004 total): 10 22 51 60 + Codes of length 09 bits (005 total): 13 23 41 42 52 + Codes of length 10 bits (005 total): 14 33 70 80 A1 + Codes of length 11 bits (001 total): A0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 035 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000338B + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000378D + Huffman table length = 83 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (003 total): 06 07 11 + Codes of length 06 bits (005 total): 00 21 30 31 B2 + Codes of length 07 bits (009 total): 12 13 32 40 41 50 51 72 74 + Codes of length 08 bits (011 total): 14 16 22 33 35 42 52 61 71 B1 B3 + Codes of length 09 bits (009 total): 15 20 23 24 60 62 81 91 C2 + Codes of length 10 bits (006 total): 10 25 36 43 75 92 + Codes of length 11 bits (004 total): 82 93 A1 A2 + Codes of length 12 bits (006 total): 34 63 64 73 C3 D2 + Codes of length 13 bits (001 total): A3 + Codes of length 14 bits (005 total): 26 45 53 65 83 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 064 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000037E2 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000076E7 + + +*** Searching Compression Signatures *** + + Signature: 014D6128740A2927C9914C433E852F5A + Signature (Rotated): 014D6128740A2927C9914C433E852F5A + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt new file mode 100644 index 0000000000..9feef52cce --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt @@ -0,0 +1,368 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue694-Decode-Exif-OutOfRange.jpg] + Filesize: [226421] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 194 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [Software ] = "PhotoFiltre 7" + [DateTime ] = "2017:08:30 22:45:26" + [ExifOffset ] = @ 0x0094 + Offset to Next IFD = 0xFC5019BC + + EXIF IFD1 @ Absolute 0xFC5019C8 + Dir Length = 0x0000 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000A0 + Dir Length = 0x0003 + [ExifVersion ] = 02.10 + [ExifImageWidth ] = 1400 + [ExifImageHeight ] = 1400 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000000C6 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000010B + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=1.54 variance=1.58) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000150 + Frame header length = 17 + Precision = 8 + Number of Lines = 1400 + Samples per Line = 1400 + Image Size = 1400 x 1400 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000163 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000184 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000023B + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000025C + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000313 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000321 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00037473.0 + + Compression stats: + Compression Ratio: 26.06:1 + Bits per pixel: 0.92:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 25384 ( 82%) + # codes of length 03 bits: 1101 ( 4%) + # codes of length 04 bits: 566 ( 2%) + # codes of length 05 bits: 758 ( 2%) + # codes of length 06 bits: 429 ( 1%) + # codes of length 07 bits: 616 ( 2%) + # codes of length 08 bits: 933 ( 3%) + # codes of length 09 bits: 1189 ( 4%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 13762 ( 89%) + # codes of length 03 bits: 146 ( 1%) + # codes of length 04 bits: 264 ( 2%) + # codes of length 05 bits: 354 ( 2%) + # codes of length 06 bits: 509 ( 3%) + # codes of length 07 bits: 335 ( 2%) + # codes of length 08 bits: 116 ( 1%) + # codes of length 09 bits: 2 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 48125 ( 26%) + # codes of length 03 bits: 20074 ( 11%) + # codes of length 04 bits: 54692 ( 30%) + # codes of length 05 bits: 21145 ( 12%) + # codes of length 06 bits: 3017 ( 2%) + # codes of length 07 bits: 14358 ( 8%) + # codes of length 08 bits: 8803 ( 5%) + # codes of length 09 bits: 2231 ( 1%) + # codes of length 10 bits: 5065 ( 3%) + # codes of length 11 bits: 1096 ( 1%) + # codes of length 12 bits: 224 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 6 ( 0%) + # codes of length 16 bits: 4924 ( 3%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 25772 ( 49%) + # codes of length 03 bits: 5924 ( 11%) + # codes of length 04 bits: 7056 ( 13%) + # codes of length 05 bits: 6378 ( 12%) + # codes of length 06 bits: 2891 ( 5%) + # codes of length 07 bits: 1200 ( 2%) + # codes of length 08 bits: 1082 ( 2%) + # codes of length 09 bits: 1030 ( 2%) + # codes of length 10 bits: 559 ( 1%) + # codes of length 11 bits: 299 ( 1%) + # codes of length 12 bits: 38 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 73 ( 0%) + # codes of length 15 bits: 67 ( 0%) + # codes of length 16 bits: 260 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 57] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1016, 0, 0] RGB=[255,255,255] @ MCU[ 40, 2] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00037472.4 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00037473 + + +*** Searching Compression Signatures *** + + Signature: 01BBB1709AC9C1F89220D955A31A8F34 + Signature (Rotated): 01BBB1709AC9C1F89220D955A31A8F34 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [PhotoFiltre 7] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[CASIO COMPUTER CO.,LTD ] [EX-Z750 ] [ ] Yes + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[PENTAX ] [PENTAX Optio S5i ] [ ] Yes + CAM:[SIGMA ] [SIGMA SD9 ] [ ] Yes + SW :[ACDSee ] [100 ] + SW :[Apple ImageIO.framework ] [100 (Best) ] + SW :[Digital Photo Professiona] [10 ] + SW :[IJG Library ] [100 ] + SW :[MS Office Pic Mgr ] [ ] + SW :[Nikon Scan ] [Excellent Qualit] + SW :[Picasa ] [100 (Maximum) ] + SW :[ZoomBrowser EX ] [highest ] + SW :[EOS Viewer Utility ] [ ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 ] + SW :[IrfanView ] [100 ] + SW :[idImager ] [100 ] + SW :[FastStone Image Viewer ] [100 ] + SW :[NeatImage ] [100 ] + SW :[Paint.NET ] [100 ] + SW :[Photomatix ] [100 ] + SW :[XnView ] [100 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt new file mode 100644 index 0000000000..8911896afa --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt @@ -0,0 +1,39 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue695-Invalid-EOI.jpg] + Filesize: [4805575] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 64 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0001 + [ExifOffset ] = @ 0x001A + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000038 + Dir Length = 0x0002 + [ExifImageWidth ] = 0x[000003E8] / 1000 + [ExifImageHeight ] = 0x[000003E8] / 1000 + +ERROR: Expected marker 0xFF, got 0x49 @ offset 0x00000056. Consider using [Tools->Img Search Fwd/Rev]. diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt new file mode 100644 index 0000000000..566291b47e --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt @@ -0,0 +1,377 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue696-Resize-Exif-OutOfRange.jpg] + Filesize: [3196058] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 201 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [Software ] = "PhotoFiltre Studio X" + [DateTime ] = "2017:09:12 23:47:30" + [ExifOffset ] = @ 0x009B + Offset to Next IFD = 0xFFFFFFFF + + EXIF IFD1 @ Absolute 0x0000001D + Dir Length = 0x4900 + Excessive # components (117440512). Limiting to first 4000. + Offset to Next IFD = 0x03011200 + + EXIF SubIFD @ Absolute 0x000000B9 + Dir Length = 0x0003 + [ExifVersion ] = 02.10 + [ExifImageWidth ] = 3000 + [ExifImageHeight ] = 3000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000000DF + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000124 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=1.54 variance=1.58) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000169 + Frame header length = 17 + Precision = 8 + Number of Lines = 3000 + Samples per Line = 3000 + Image Size = 3000 x 3000 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000017C + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000019D + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000254 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000275 + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000032C + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000033A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0030C498.0 + + Compression stats: + Compression Ratio: 8.45:1 + Bits per pixel: 2.84:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 35306 ( 25%) + # codes of length 03 bits: 79378 ( 56%) + # codes of length 04 bits: 10642 ( 8%) + # codes of length 05 bits: 5371 ( 4%) + # codes of length 06 bits: 3913 ( 3%) + # codes of length 07 bits: 2829 ( 2%) + # codes of length 08 bits: 2486 ( 2%) + # codes of length 09 bits: 1451 ( 1%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 45165 ( 64%) + # codes of length 03 bits: 10069 ( 14%) + # codes of length 04 bits: 6960 ( 10%) + # codes of length 05 bits: 3541 ( 5%) + # codes of length 06 bits: 2100 ( 3%) + # codes of length 07 bits: 1345 ( 2%) + # codes of length 08 bits: 1100 ( 2%) + # codes of length 09 bits: 324 ( 0%) + # codes of length 10 bits: 84 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1981662 ( 53%) + # codes of length 03 bits: 213036 ( 6%) + # codes of length 04 bits: 749857 ( 20%) + # codes of length 05 bits: 410362 ( 11%) + # codes of length 06 bits: 173055 ( 5%) + # codes of length 07 bits: 94282 ( 3%) + # codes of length 08 bits: 61648 ( 2%) + # codes of length 09 bits: 36705 ( 1%) + # codes of length 10 bits: 19723 ( 1%) + # codes of length 11 bits: 10118 ( 0%) + # codes of length 12 bits: 2157 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 211 ( 0%) + # codes of length 16 bits: 9772 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 425513 ( 38%) + # codes of length 03 bits: 127308 ( 11%) + # codes of length 04 bits: 204956 ( 18%) + # codes of length 05 bits: 171523 ( 15%) + # codes of length 06 bits: 89715 ( 8%) + # codes of length 07 bits: 30159 ( 3%) + # codes of length 08 bits: 25054 ( 2%) + # codes of length 09 bits: 22104 ( 2%) + # codes of length 10 bits: 10243 ( 1%) + # codes of length 11 bits: 4250 ( 0%) + # codes of length 12 bits: 210 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 1829 ( 0%) + # codes of length 15 bits: 1498 ( 0%) + # codes of length 16 bits: 2262 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[127] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 992, -112, 17] RGB=[254,255,227] @ MCU[ 35, 79] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0030C497.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0030C498 + + +*** Searching Compression Signatures *** + + Signature: 01BBB1709AC9C1F89220D955A31A8F34 + Signature (Rotated): 01BBB1709AC9C1F89220D955A31A8F34 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [PhotoFiltre Studio X] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[CASIO COMPUTER CO.,LTD ] [EX-Z750 ] [ ] Yes + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[PENTAX ] [PENTAX Optio S5i ] [ ] Yes + CAM:[SIGMA ] [SIGMA SD9 ] [ ] Yes + SW :[ACDSee ] [100 ] + SW :[Apple ImageIO.framework ] [100 (Best) ] + SW :[Digital Photo Professiona] [10 ] + SW :[IJG Library ] [100 ] + SW :[MS Office Pic Mgr ] [ ] + SW :[Nikon Scan ] [Excellent Qualit] + SW :[Picasa ] [100 (Maximum) ] + SW :[ZoomBrowser EX ] [highest ] + SW :[EOS Viewer Utility ] [ ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 ] + SW :[IrfanView ] [100 ] + SW :[idImager ] [100 ] + SW :[FastStone Image Viewer ] [100 ] + SW :[NeatImage ] [100 ] + SW :[Paint.NET ] [100 ] + SW :[Photomatix ] [100 ] + SW :[XnView ] [100 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt new file mode 100644 index 0000000000..dc283bfcfc --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt @@ -0,0 +1,446 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue721-InvalidAPP0.jpg] + Filesize: [1225163] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 806 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0007 + [Make ] = "NIKON CORPORATION" + [Model ] = "NIKON D300S" + [Software ] = "Adobe Bridge CS6 (Windows)" + [DateTime ] = "2017:06:07 16:49:51" + [Artist ] = ""Evgeniy Ivahiv Mr.Ivas"" + [Copyright ] = "Evgeniy Ivahiv Erich Krause" + [ExifOffset ] = @ 0x00EC + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000F8 + Dir Length = 0x0022 + [ExposureTime ] = 1/160 s + [FNumber ] = F10.0 + [ExposureProgram ] = Manual + [ISOSpeedRatings ] = 200 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2017:06:06 11:29:53" + [ShutterSpeedValue ] = 7321928/1000000 + [ApertureValue ] = 6643856/1000000 + [ExposureBiasValue ] = -3.00 eV + [MaxApertureValue ] = 50/10 + [MeteringMode ] = CenterWeightedAverage + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 48 mm + [SubSecTimeOriginal ] = "24" + [ColorSpace ] = Uncalibrated + [ExifImageWidth ] = 2304 + [ExifImageHeight ] = 2998 + [SensingMethod ] = One-chip color area sensor + [FileSource ] = DSC + [SceneType ] = A directly photographed image + [ExposureMode ] = Manual exposure + [WhiteBalance ] = Manual white balance + [DigitalZoomRatio ] = 1/1 + [FocalLengthIn35mmFilm ] = 72 + [SceneCaptureType ] = Standard + [GainControl ] = 0 + [Contrast ] = 0 + [Saturation ] = 0 + [Sharpness ] = 2 + [SubjectDistanceRange ] = 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x0000032A + Length = 4442 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00001486 + Length = 160 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x0068] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 4 + IPTC [002:055] Date Created = "20170606" + IPTC [002:060] Time Created = "112953" + IPTC [002:080] By-line = "Evgeniy Ivahiv Mr.Ivas" + IPTC [002:116] Copyright Notice = "Evgeniy Ivahiv Erich Krause" + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x59 13 63 D2 BD 08 14 B4 2B E3 4F 37 D7 52 D2 6F | Y.c.....+.O7.R.o + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00001528 + Length = 3160 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3144 bytes + Preferred CMM Type : 'Lino' (0x4C696E6F) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1998-02-09 06:49:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Microsoft Corporation ('MSFT' (0x4D534654)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'IEC ' (0x49454320) + Device Model : 'sRGB' (0x73524742) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'HP ' (0x48502020) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00002182 + Length = 12 + Identifier = [Adobe_CM] + Not known APP0 type. Skipping remainder. + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002190 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 7 11 14 17 22 17 + DQT, Row #1: 4 5 6 10 14 19 12 12 + DQT, Row #2: 7 6 8 14 19 12 12 12 + DQT, Row #3: 11 10 14 19 12 12 12 12 + DQT, Row #4: 14 14 19 12 12 12 12 12 + DQT, Row #5: 17 19 12 12 12 12 12 12 + DQT, Row #6: 22 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 83.88 (scaling=32.24 variance=430.71) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 9 19 34 20 20 17 17 + DQT, Row #1: 9 12 19 14 14 12 12 12 + DQT, Row #2: 19 19 14 14 12 12 12 12 + DQT, Row #3: 34 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 89.11 (scaling=21.78 variance=377.49) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00002216 + Length = 4 + interval = 288 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0000221C + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000222C + Frame header length = 17 + Precision = 8 + Number of Lines = 2998 + Samples per Line = 2304 + Image Size = 2304 x 2998 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000223F + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (004 total): 03 04 05 06 + Codes of length 04 bits (003 total): 02 07 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (000 total): + Codes of length 09 bits (002 total): 07 08 + Codes of length 10 bits (003 total): 09 0A 0B + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 11 + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (004 total): 04 12 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (008 total): 05 13 22 71 81 91 A1 F0 + Codes of length 08 bits (004 total): 06 14 B1 C1 + Codes of length 09 bits (005 total): 23 32 D1 E1 F1 + Codes of length 10 bits (002 total): 07 42 + Codes of length 11 bits (003 total): 15 24 52 + Codes of length 12 bits (002 total): 33 62 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 16 + Codes of length 16 bits (125 total): 34 43 72 82 92 A2 08 17 53 B2 C2 25 D2 E2 44 83 + 84 F2 09 0A 18 19 1A 26 27 28 29 2A 35 36 37 38 + 39 3A 45 46 47 48 49 4A 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 85 + 86 87 88 89 8A 93 94 95 96 97 98 B3 C3 D3 99 9A + A3 A4 A5 A6 A7 A8 A9 AA B4 B5 B6 B7 B8 B9 BA C4 + C5 C6 C7 C8 C9 CA D4 D5 D6 D7 D8 D9 DA E3 E4 E5 + E6 E7 E8 E9 EA F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 02 11 + Codes of length 05 bits (001 total): 03 + Codes of length 06 bits (003 total): 12 21 31 + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (005 total): 04 13 51 61 71 + Codes of length 09 bits (002 total): 81 F0 + Codes of length 10 bits (006 total): 22 91 A1 B1 C1 D1 + Codes of length 11 bits (003 total): 14 32 E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (127 total): 05 06 07 08 09 0A 15 16 17 18 19 1A 23 24 25 26 + 27 28 29 2A 33 34 35 36 37 38 39 3A 42 43 44 45 + 46 47 48 49 4A 52 53 54 55 56 57 58 59 5A 62 63 + 64 65 66 67 68 69 6A 72 73 74 75 76 77 78 79 7A + 82 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 + 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 + B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 + D5 D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA + Codes of length 15 bits (009 total): F2 F3 F4 F5 F6 F7 F8 F9 FA + Codes of length 16 bits (000 total): + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000023E3 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000023F1 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + +*** ERROR: Overread scan segment (after bitstring)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.6 +*** ERROR: Bad scan data in MCU(272,16): Lum CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(2176,128) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(272,16): Chr(Cb) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(2176,128) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(272,16): Chr(Cr) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(2176,128) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,17): Lum CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,136) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,17): Chr(Cb) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,136) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,17): Chr(Cr) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,136) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,18): Lum CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,144) + Only reported first 20 instances of this message... + + Compression stats: + Compression Ratio: 3031.33:1 + Bits per pixel: 0.01:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 4841 ( 99%) + # codes of length 03 bits: 33 ( 1%) + # codes of length 04 bits: 6 ( 0%) + # codes of length 05 bits: 1 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 9732 (100%) + # codes of length 02 bits: 23 ( 0%) + # codes of length 03 bits: 5 ( 0%) + # codes of length 04 bits: 0 ( 0%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 274 ( 5%) + # codes of length 03 bits: 297 ( 5%) + # codes of length 04 bits: 4903 ( 85%) + # codes of length 05 bits: 88 ( 2%) + # codes of length 06 bits: 26 ( 0%) + # codes of length 07 bits: 98 ( 2%) + # codes of length 08 bits: 25 ( 0%) + # codes of length 09 bits: 4 ( 0%) + # codes of length 10 bits: 14 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 2 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 17 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 9760 (100%) + # codes of length 02 bits: 5 ( 0%) + # codes of length 03 bits: 0 ( 0%) + # codes of length 04 bits: 14 ( 0%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 2 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[128] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1014, 0, 0] RGB=[254,254,254] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 17 + Next position in scan buffer: Offset 0x00003EA5.1 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0012B1C9 + + +*** Searching Compression Signatures *** + + Signature: 01A20F69263117021CD16AEF44D6E650 + Signature (Rotated): 01A20F69263117021CD16AEF44D6E650 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [NIKON] [NIKON D300S] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Bridge CS6 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt new file mode 100644 index 0000000000..92adfb3159 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt @@ -0,0 +1,519 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue723-Ordered-Interleaved-Progressive-A.jpg] + Filesize: [42798] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 2 1 1 2 2 4 5 6 + DQT, Row #1: 1 1 1 2 3 6 6 6 + DQT, Row #2: 1 1 2 2 4 6 7 6 + DQT, Row #3: 1 2 2 3 5 9 8 6 + DQT, Row #4: 2 2 4 6 7 11 10 8 + DQT, Row #5: 2 4 6 6 8 10 11 9 + DQT, Row #6: 5 6 8 9 10 12 12 10 + DQT, Row #7: 7 9 10 10 11 10 10 10 + Approx quality factor = 95.04 (scaling=9.93 variance=1.25) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 2 2 2 5 10 10 10 10 + DQT, Row #1: 2 2 3 7 10 10 10 10 + DQT, Row #2: 2 3 6 10 10 10 10 10 + DQT, Row #3: 5 7 10 10 10 10 10 10 + DQT, Row #4: 10 10 10 10 10 10 10 10 + DQT, Row #5: 10 10 10 10 10 10 10 10 + DQT, Row #6: 10 10 10 10 10 10 10 10 + DQT, Row #7: 10 10 10 10 10 10 10 10 + Approx quality factor = 94.91 (scaling=10.18 variance=0.26) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 600 + Samples per Line = 600 + Image Size = 600 x 600 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 01 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (005 total): 04 05 06 07 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000D0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000A58 + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 01 02 + Codes of length 04 bits (003 total): 03 04 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000A75 + Scan header length = 10 + Number of img components = 2 + Component[1]: selector=0x02, table=1(DC),0(AC) + Component[2]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000E55 + Huffman table length = 37 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (005 total): 02 04 05 11 12 + Codes of length 04 bits (004 total): 00 01 03 06 + Codes of length 05 bits (001 total): 30 + Codes of length 06 bits (005 total): 10 13 14 15 16 + Codes of length 07 bits (001 total): 40 + Codes of length 08 bits (001 total): 20 + Codes of length 09 bits (001 total): A0 + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 018 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E7C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 2 + Successive approximation = 0x03 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000015BD + Huffman table length = 82 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (004 total): 00 04 05 11 + Codes of length 05 bits (002 total): 12 21 + Codes of length 06 bits (002 total): 13 31 + Codes of length 07 bits (011 total): 06 10 14 22 30 32 40 41 51 61 92 + Codes of length 08 bits (012 total): 15 23 25 52 53 54 71 73 91 A1 B1 C1 + Codes of length 09 bits (007 total): 20 24 33 42 72 81 93 + Codes of length 10 bits (006 total): 43 44 55 62 63 A2 + Codes of length 11 bits (003 total): 82 83 D1 + Codes of length 12 bits (006 total): 16 26 34 50 A0 B2 + Codes of length 13 bits (007 total): 35 45 64 84 A3 C2 E1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 063 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001611 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 3 .. 63 + Successive approximation = 0x03 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002E3F + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 11 + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (004 total): 10 41 51 61 + Codes of length 06 bits (005 total): 20 71 81 91 F0 + Codes of length 07 bits (005 total): 30 A1 B1 C1 D1 + Codes of length 08 bits (001 total): F1 + Codes of length 09 bits (001 total): E1 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (001 total): A0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002E6B + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x32 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003F38 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (004 total): 10 71 81 91 + Codes of length 08 bits (001 total): A1 + Codes of length 09 bits (005 total): 30 B1 C1 D1 F0 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (003 total): 20 40 A0 + Codes of length 14 bits (001 total): 50 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003F65 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00005B9B + Huffman table length = 58 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (003 total): 04 11 12 + Codes of length 05 bits (001 total): 21 + Codes of length 06 bits (005 total): 05 13 14 31 51 + Codes of length 07 bits (005 total): 10 15 20 30 41 + Codes of length 08 bits (005 total): 22 23 32 33 71 + Codes of length 09 bits (005 total): 24 34 61 81 F0 + Codes of length 10 bits (008 total): 80 91 A1 B1 C1 D1 E1 F1 + Codes of length 11 bits (003 total): 42 52 62 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 039 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00005BD7 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006270 + Huffman table length = 57 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (004 total): 00 02 03 11 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (002 total): 05 30 + Codes of length 07 bits (004 total): 10 13 14 20 + Codes of length 08 bits (003 total): 32 41 51 + Codes of length 09 bits (007 total): 15 22 23 61 71 81 F0 + Codes of length 10 bits (002 total): 91 A1 + Codes of length 11 bits (004 total): 24 25 33 80 + Codes of length 12 bits (007 total): 42 62 B1 C1 D1 E1 F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 038 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000062AB + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006827 + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (001 total): 71 + Codes of length 08 bits (004 total): 81 91 A1 B1 + Codes of length 09 bits (003 total): 30 C1 D1 + Codes of length 10 bits (001 total): F0 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): 10 + Codes of length 13 bits (000 total): + Codes of length 14 bits (003 total): 40 A0 F1 + Codes of length 15 bits (001 total): 20 + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006853 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000099AB + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (003 total): 31 41 61 + Codes of length 06 bits (003 total): 10 51 91 + Codes of length 07 bits (004 total): 20 71 81 B1 + Codes of length 08 bits (002 total): 30 A1 + Codes of length 09 bits (002 total): C1 F0 + Codes of length 10 bits (003 total): 80 E1 F1 + Codes of length 11 bits (001 total): D1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000099D6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000A0BC + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (001 total): 41 + Codes of length 06 bits (004 total): 10 51 61 71 + Codes of length 07 bits (002 total): 30 91 + Codes of length 08 bits (002 total): 20 81 + Codes of length 09 bits (002 total): A1 B1 + Codes of length 10 bits (002 total): C1 D1 + Codes of length 11 bits (003 total): 40 80 E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000A0E7 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000A72C + + +*** Searching Compression Signatures *** + + Signature: 01E764F3ECB6C14A51FF83F1FF6D546B + Signature (Rotated): 01E6610D026E8E6FE4BECEA9B3328A63 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5400 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[PENTAX ] [PENTAX K10D ] [ ] No + CAM:[SAMSUNG TECHWIN ] [Pro 815 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV 7, NV 7 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV10, NV10 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-F828 ] [ ] No + CAM:[SONY ] [DSC-H1 ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H5 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-L1 ] [ ] No + CAM:[SONY ] [DSC-N1 ] [ ] No + CAM:[SONY ] [DSC-P150 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-V3 ] [ ] No + CAM:[SONY ] [DSC-W55 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Apple ImageIO.framework ] [084 ] + SW :[IJG Library ] [095 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [095 ] + SW :[IrfanView ] [095 ] + SW :[idImager ] [095 ] + SW :[FastStone Image Viewer ] [095 ] + SW :[NeatImage ] [095 ] + SW :[Paint.NET ] [095 ] + SW :[Photomatix ] [095 ] + SW :[XnView ] [095 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt new file mode 100644 index 0000000000..bcbe9f7f1d --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt @@ -0,0 +1,477 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue723-Ordered-Interleaved-Progressive-B.jpg] + Filesize: [36937] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 600 + Samples per Line = 600 + Image Size = 600 x 600 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 30 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (000 total): + Codes of length 04 bits (007 total): 02 03 04 05 06 07 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000D1 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000A95 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 04 05 + Codes of length 04 bits (003 total): 01 03 06 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000AB3 + Scan header length = 10 + Number of img components = 2 + Component[1]: selector=0x02, table=1(DC),0(AC) + Component[2]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000E60 + Huffman table length = 54 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (006 total): 00 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 11 12 13 + Codes of length 06 bits (002 total): 21 50 + Codes of length 07 bits (004 total): 07 10 14 15 + Codes of length 08 bits (004 total): 20 22 23 31 + Codes of length 09 bits (005 total): 16 24 30 32 36 + Codes of length 10 bits (003 total): 25 40 41 + Codes of length 11 bits (004 total): 17 42 43 80 + Codes of length 12 bits (003 total): 26 33 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 035 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E98 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001E73 + Huffman table length = 75 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (002 total): 00 11 + Codes of length 05 bits (002 total): 04 12 + Codes of length 06 bits (005 total): 13 21 31 41 51 + Codes of length 07 bits (006 total): 10 22 52 61 71 81 + Codes of length 08 bits (010 total): 05 14 20 32 42 50 91 A1 B1 C1 + Codes of length 09 bits (005 total): 23 33 62 72 D1 + Codes of length 10 bits (010 total): 24 30 40 53 63 73 82 92 E1 F0 + Codes of length 11 bits (005 total): 15 34 35 43 A2 + Codes of length 12 bits (004 total): 64 74 80 B2 + Codes of length 13 bits (003 total): 60 93 F1 + Codes of length 14 bits (001 total): A3 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 056 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001EC0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003A1E + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (005 total): 10 51 61 71 81 + Codes of length 07 bits (004 total): 50 91 A1 B1 + Codes of length 08 bits (002 total): C1 F0 + Codes of length 09 bits (003 total): 20 D1 E1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): 40 + Codes of length 12 bits (001 total): 80 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003A4A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00005386 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (001 total): 51 + Codes of length 07 bits (003 total): 61 71 81 + Codes of length 08 bits (004 total): 50 91 A1 B1 + Codes of length 09 bits (002 total): 10 C1 + Codes of length 10 bits (003 total): D1 E1 F0 + Codes of length 11 bits (000 total): + Codes of length 12 bits (003 total): 20 80 F1 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000053B3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007B5B + Huffman table length = 50 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (003 total): 13 31 40 + Codes of length 07 bits (003 total): 06 22 41 + Codes of length 08 bits (002 total): 14 32 + Codes of length 09 bits (004 total): 10 16 23 33 + Codes of length 10 bits (005 total): 15 20 42 60 61 + Codes of length 11 bits (005 total): 24 34 50 51 52 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007B8F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 12 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000081EE + Huffman table length = 49 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (004 total): 21 31 41 51 + Codes of length 05 bits (003 total): 02 61 71 + Codes of length 06 bits (007 total): 10 40 81 91 A1 B1 C1 + Codes of length 07 bits (003 total): D1 E1 F0 + Codes of length 08 bits (003 total): 03 50 F1 + Codes of length 09 bits (004 total): 12 22 30 60 + Codes of length 10 bits (003 total): 20 32 70 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 030 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008221 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 13 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000084F2 + Huffman table length = 48 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (003 total): 00 11 12 + Codes of length 06 bits (003 total): 06 21 31 + Codes of length 07 bits (003 total): 13 22 40 + Codes of length 08 bits (002 total): 14 41 + Codes of length 09 bits (005 total): 07 10 15 32 50 + Codes of length 10 bits (003 total): 42 60 61 + Codes of length 11 bits (005 total): 20 23 33 43 51 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 029 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008524 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 12 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008C10 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (004 total): 02 31 41 51 + Codes of length 06 bits (002 total): 61 71 + Codes of length 07 bits (009 total): 03 12 40 81 91 A1 B1 C1 D1 + Codes of length 08 bits (003 total): 10 E1 F0 + Codes of length 09 bits (003 total): 22 32 F1 + Codes of length 10 bits (004 total): 04 50 52 70 + Codes of length 11 bits (003 total): 20 42 60 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008C45 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 13 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00009047 + + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] Yes + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt new file mode 100644 index 0000000000..c76b744313 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt @@ -0,0 +1,484 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue723-Ordered-Interleaved-Progressive-C.jpg] + Filesize: [46799] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 38 x 38 DPcm (dots per cm) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 2 1 1 2 2 4 5 6 + DQT, Row #1: 1 1 1 2 3 6 6 6 + DQT, Row #2: 1 1 2 2 4 6 7 6 + DQT, Row #3: 1 2 2 3 5 9 8 6 + DQT, Row #4: 2 2 4 6 7 11 10 8 + DQT, Row #5: 2 4 6 6 8 10 11 9 + DQT, Row #6: 5 6 8 9 10 12 12 10 + DQT, Row #7: 7 9 10 10 11 10 10 10 + Approx quality factor = 95.04 (scaling=9.93 variance=1.25) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 2 2 2 5 10 10 10 10 + DQT, Row #1: 2 2 3 7 10 10 10 10 + DQT, Row #2: 2 3 6 10 10 10 10 10 + DQT, Row #3: 5 7 10 10 10 10 10 10 + DQT, Row #4: 10 10 10 10 10 10 10 10 + DQT, Row #5: 10 10 10 10 10 10 10 10 + DQT, Row #6: 10 10 10 10 10 10 10 10 + DQT, Row #7: 10 10 10 10 10 10 10 10 + Approx quality factor = 94.91 (scaling=10.18 variance=0.26) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 517 + Samples per Line = 502 + Image Size = 502 x 517 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 30 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 06 + Codes of length 04 bits (004 total): 04 05 07 08 + Codes of length 05 bits (003 total): 02 03 09 + Codes of length 06 bits (001 total): 01 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000D1 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000858 + Huffman table length = 29 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 05 + Codes of length 04 bits (005 total): 02 03 04 06 07 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000877 + Scan header length = 10 + Number of img components = 2 + Component[1]: selector=0x02, table=1(DC),0(AC) + Component[2]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000012C2 + Huffman table length = 67 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (004 total): 01 02 04 05 + Codes of length 04 bits (002 total): 00 06 + Codes of length 05 bits (001 total): 11 + Codes of length 06 bits (002 total): 07 12 + Codes of length 07 bits (004 total): 13 14 21 50 + Codes of length 08 bits (004 total): 08 15 22 31 + Codes of length 09 bits (002 total): 17 23 + Codes of length 10 bits (006 total): 10 16 20 24 32 41 + Codes of length 11 bits (008 total): 25 33 34 42 51 52 54 62 + Codes of length 12 bits (004 total): 26 30 35 40 + Codes of length 13 bits (005 total): 18 27 37 55 56 + Codes of length 14 bits (005 total): 44 53 61 70 80 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 048 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001307 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 12 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002FBE + Huffman table length = 80 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (005 total): 13 22 41 51 61 + Codes of length 07 bits (011 total): 05 10 14 32 50 71 81 91 A1 B1 C1 + Codes of length 08 bits (007 total): 20 23 42 52 62 82 D1 + Codes of length 09 bits (009 total): 15 30 33 53 72 92 A2 B2 E1 + Codes of length 10 bits (006 total): 24 40 43 73 C2 E2 + Codes of length 11 bits (004 total): 06 63 D2 F0 + Codes of length 12 bits (005 total): 25 54 75 A3 B3 + Codes of length 13 bits (005 total): 44 64 70 80 83 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 061 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003010 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 13 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000048A9 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (001 total): 41 + Codes of length 06 bits (003 total): 51 61 71 + Codes of length 07 bits (003 total): 10 81 A1 + Codes of length 08 bits (004 total): 50 91 B1 C1 + Codes of length 09 bits (003 total): 20 D1 F0 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (001 total): 70 + Codes of length 14 bits (001 total): 80 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000048D6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000060D3 + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (001 total): 71 + Codes of length 08 bits (004 total): 50 81 91 A1 + Codes of length 09 bits (002 total): 10 B1 + Codes of length 10 bits (002 total): C1 F0 + Codes of length 11 bits (002 total): D1 F1 + Codes of length 12 bits (003 total): 30 70 E1 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000060FF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007FD1 + Huffman table length = 54 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (004 total): 01 02 04 05 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (002 total): 06 11 + Codes of length 06 bits (006 total): 07 12 13 21 31 50 + Codes of length 07 bits (001 total): 14 + Codes of length 08 bits (002 total): 15 22 + Codes of length 09 bits (005 total): 10 23 32 33 41 + Codes of length 10 bits (003 total): 16 17 20 + Codes of length 11 bits (002 total): 24 34 + Codes of length 12 bits (007 total): 25 26 30 40 42 51 70 + Codes of length 13 bits (001 total): 80 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 035 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008009 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 8 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008F76 + Huffman table length = 59 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (004 total): 03 12 41 51 + Codes of length 06 bits (003 total): 61 71 81 + Codes of length 07 bits (005 total): 10 22 50 91 A1 + Codes of length 08 bits (007 total): 32 52 B1 C1 D1 F0 F1 + Codes of length 09 bits (002 total): 04 13 + Codes of length 10 bits (004 total): 20 23 42 72 + Codes of length 11 bits (006 total): 62 70 80 82 92 E1 + Codes of length 12 bits (003 total): 30 60 A2 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 040 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008FB3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 9 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00009B28 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (004 total): 01 02 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 00 07 11 + Codes of length 06 bits (003 total): 12 13 31 + Codes of length 07 bits (003 total): 08 21 50 + Codes of length 08 bits (003 total): 10 14 15 + Codes of length 09 bits (004 total): 20 23 32 41 + Codes of length 10 bits (001 total): 16 + Codes of length 11 bits (003 total): 22 24 40 + Codes of length 12 bits (005 total): 17 18 33 34 70 + Codes of length 13 bits (001 total): 80 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00009B5D + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 8 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000AB99 + Huffman table length = 62 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 11 + Codes of length 04 bits (002 total): 03 21 + Codes of length 05 bits (004 total): 12 31 41 51 + Codes of length 06 bits (003 total): 04 61 71 + Codes of length 07 bits (005 total): 10 22 32 50 81 + Codes of length 08 bits (004 total): 13 91 A1 B1 + Codes of length 09 bits (008 total): 20 23 42 52 62 72 C1 D1 + Codes of length 10 bits (005 total): 05 14 92 E1 F0 + Codes of length 11 bits (003 total): 30 33 F1 + Codes of length 12 bits (005 total): 70 80 82 90 A2 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 043 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000ABD9 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 9 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000B6CD + + +*** Searching Compression Signatures *** + + Signature: 01E764F3ECB6C14A51FF83F1FF6D546B + Signature (Rotated): 01E6610D026E8E6FE4BECEA9B3328A63 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5400 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[PENTAX ] [PENTAX K10D ] [ ] No + CAM:[SAMSUNG TECHWIN ] [Pro 815 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV 7, NV 7 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV10, NV10 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-F828 ] [ ] No + CAM:[SONY ] [DSC-H1 ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H5 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-L1 ] [ ] No + CAM:[SONY ] [DSC-N1 ] [ ] No + CAM:[SONY ] [DSC-P150 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-V3 ] [ ] No + CAM:[SONY ] [DSC-W55 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Apple ImageIO.framework ] [084 ] + SW :[IJG Library ] [095 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [095 ] + SW :[IrfanView ] [095 ] + SW :[idImager ] [095 ] + SW :[FastStone Image Viewer ] [095 ] + SW :[NeatImage ] [095 ] + SW :[Paint.NET ] [095 ] + SW :[Photomatix ] [095 ] + SW :[XnView ] [095 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt new file mode 100644 index 0000000000..6070e1cdab --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt @@ -0,0 +1,772 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\issue750-exif-load.jpg] + Filesize: [36885] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 3656 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0010 + [Make ] = "Canon" + [Model ] = "Canon EOS 70D" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 720000/10000 + [YResolution ] = 720000/10000 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CS6 (Windows)" + [DateTime ] = "2018:02:28 17:51:59" + [YCbCrPositioning ] = Centered + [ExifOffset ] = @ 0x012C + [GPSOffset ] = @ 0x04C8 + Offset to Next IFD = 0x000004DC + + EXIF IFD1 @ Absolute 0x000004E8 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x053A = @ 0x0546 + [JpegIFByteCount ] = 0x[00000906] / 2310 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000138 + Dir Length = 0x0025 + [ExposureTime ] = 1/60 s + [FNumber ] = F11.0 + [ExposureProgram ] = Manual + [ISOSpeedRatings ] = 100 + [ExifVersion ] = 02.30 + [DateTimeOriginal ] = "2017:09:14 14:41:54" + [DateTimeDigitized ] = "2017:09:14 14:41:54" + [ComponentsConfiguration ] = [Y Cb Cr .] + [ShutterSpeedValue ] = 393216/65536 + [ApertureValue ] = 458752/65536 + [ExposureBiasValue ] = 0.00 eV + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 50 mm + [UserComment ] = "" + [SubSecTime ] = "277" + [SubSecTimeOriginal ] = "00" + [SubSecTimeDigitized ] = "00" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 0x[000001D3] / 467 + [ExifImageHeight ] = 0x[000002BC] / 700 + [ExifInteroperabilityOffset ] = @ 0x04A8 + [FocalPlaneXResolution ] = 5472000/899 + [FocalPlaneYResolution ] = 3648000/599 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Manual exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + + EXIF GPSIFD @ Absolute 0x000004D4 + Dir Length = 0x0001 + [GPSVersionID ] = 2.3.0.0 + + EXIF InteropIFD @ Absolute 0x000004B4 + Dir Length = 0x0002 + [InteroperabilityIndex ] = "R98" + [InteroperabilityVersion ] = 01.00 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000E4C + Length = 4648 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x002C] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 51658 + IPTC [002:055] Date Created = "20170914" + IPTC [002:060] Time Created = "144154+0000" + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x8B 58 80 D1 16 85 C7 6D 47 04 59 0B 61 59 FA 69 | .X.....mG.Y.aY.i + 8BIM: [0x043A] Name="" Len=[0x00E5] DefinedName="Print Information" + Print Information = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 0B 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 00 00 00 05 00 00 00 | intOutput....... + | 0x00 50 73 74 53 62 6F 6F 6C 01 00 00 00 00 49 6E | .PstSbool.....In + | 0x74 65 65 6E 75 6D 00 00 00 00 49 6E 74 65 00 00 | teenum....Inte.. + | 0x00 00 43 6C 72 6D 00 00 00 0F 70 72 69 6E 74 53 | ..Clrm....printS + | 0x69 78 74 65 65 6E 42 69 74 62 6F 6F 6C 00 00 00 | ixteenBitbool... + | 0x00 0B 70 72 69 6E 74 65 72 4E 61 6D 65 54 45 58 | ..printerNameTEX + | 0x54 00 00 00 01 00 00 00 00 00 0F 70 72 69 6E 74 | T..........print + | ... + 8BIM: [0x043B] Name="" Len=[0x022D] DefinedName="Print Style" + Print Style = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 12 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 4F 70 74 69 6F 6E 73 | intOutputOptions + | 0x00 00 00 17 00 00 00 00 43 70 74 6E 62 6F 6F 6C | ........Cptnbool + | 0x00 00 00 00 00 43 6C 62 72 62 6F 6F 6C 00 00 00 | .....Clbrbool... + | 0x00 00 52 67 73 4D 62 6F 6F 6C 00 00 00 00 00 43 | ..RgsMbool.....C + | 0x72 6E 43 62 6F 6F 6C 00 00 00 00 00 43 6E 74 43 | rnCbool.....CntC + | 0x62 6F 6F 6C 00 00 00 00 00 4C 62 6C 73 62 6F 6F | bool.....Lblsboo + | 0x6C 00 00 00 00 00 4E 67 74 76 62 6F 6F 6C 00 00 | l.....Ngtvbool.. + | ... + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 72 pixels per inch + Width unit = cm + Vertical resolution = 72 pixels per inch + Height unit = cm + 8BIM: [0x0426] Name="" Len=[0x000E] DefinedName="Print scale" + Style = centered + X location = 0.00000 + Y location = 0.00000 + Scale = 1.00000 + 8BIM: [0x040D] Name="" Len=[0x0004] DefinedName="Global Angle" + Global Angle = 30 degrees + 8BIM: [0x0419] Name="" Len=[0x0004] DefinedName="Global Altitude" + Global Altitude = 30 + 8BIM: [0x03F3] Name="" Len=[0x0009] DefinedName="Print flags" + Labels = false + Crop marks = false + Color bars = false + Registration marks = false + Negative = false + Flip = false + Interpolate = false + Caption = false + Print flags = true + 8BIM: [0x2710] Name="" Len=[0x000A] DefinedName="Print flags information" + Version = 1 + Center crop marks = 0 + Reserved = 0 + Bleed width value = 0 + Bleed width scale = 2 + 8BIM: [0x03F5] Name="" Len=[0x0048] DefinedName="Color halftoning information" + Color halftoning information = + | 0x00 2F 66 66 00 01 00 6C 66 66 00 06 00 00 00 00 | ./ff...lff...... + | 0x00 01 00 2F 66 66 00 01 00 A1 99 9A 00 06 00 00 | .../ff.......... + | 0x00 00 00 01 00 32 00 00 00 01 00 5A 00 00 00 06 | .....2.....Z.... + | 0x00 00 00 00 00 01 00 35 00 00 00 01 00 2D 00 00 | .......5.....-.. + | 0x00 06 00 00 00 00 00 01 | ........ + 8BIM: [0x03F8] Name="" Len=[0x0070] DefinedName="Color transfer functions" + Color transfer functions = + | 0x00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF 03 E8 00 00 00 00 FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF 03 E8 00 00 00 00 FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0x03 E8 00 00 00 00 FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF 03 E8 00 00 | ................ + 8BIM: [0x0408] Name="" Len=[0x0010] DefinedName="Grid and guides information" + Version = 1 + Grid Horizontal = 576 + Grid Vertical = 576 + Number of Guide Resources = 0 + 8BIM: [0x041E] Name="" Len=[0x0004] DefinedName="URL List" + URL List = | 0x00 00 00 00 | .... + 8BIM: [0x041A] Name="" Len=[0x0341] DefinedName="Slices" + Slice Header: + Version = 6 + Bound Rect (top) = 0 + Bound Rect (left) = 0 + Bound Rect (bottom) = 700 + Bound Rect (right) = 467 + Name of group of slices = "513566" + Number of slices = 1 + ----- + Slice #0: + Slice Resource: + ID = 0 + Group ID = 0 + Origin = 0 + Name = "" + Type = 1 + Position (top) = 0 + Position (left) = 0 + Position (bottom) = 467 + Position (right) = 700 + URL = "" + Target = "" + Message = "" + Alt Tag = "" + Cell text is HTML = true + Cell text = "" + Horizontal alignment = 0 + Vertical alignment = 0 + Alpha color = 0 + Red = 0 + Green = 0 + Blue = 0 + Descriptor version = 16 + Descriptor: + Name from classID = "" + classID = "null" + Num items in descriptor = 2 + ----- + Descriptor item #0: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 700 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 467 + ----- + Descriptor item #1: + Key = "slices" + OSType key = "VlLs" + Num items in list = 1 + ----- + Item #0: + OSType key = "" + Descriptor: + Name from classID = "" + classID = "slice" + Num items in descriptor = 18 + ----- + Descriptor item #0: + Key = "sliceID" + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "groupID" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "origin" + OSType key = "enum" + Type = "ESliceOrigin" + Enum = "autoGenerated" + Descriptor item #3: + Key = "Type" + OSType key = "enum" + Type = "ESliceType" + Enum = "Img " + Descriptor item #4: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 700 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 467 + ----- + Descriptor item #5: + Key = "url" + OSType key = "TEXT" + String = "" + Descriptor item #6: + Key = "null" + OSType key = "TEXT" + String = "" + Descriptor item #7: + Key = "Msge" + OSType key = "TEXT" + String = "" + Descriptor item #8: + Key = "altTag" + OSType key = "TEXT" + String = "" + Descriptor item #9: + Key = "cellTextIsHTML" + OSType key = "bool" + Value = true + Descriptor item #10: + Key = "cellText" + OSType key = "TEXT" + String = "" + Descriptor item #11: + Key = "horzAlign" + OSType key = "enum" + Type = "ESliceHorzAlign" + Enum = "default" + Descriptor item #12: + Key = "vertAlign" + OSType key = "enum" + Type = "ESliceVertAlign" + Enum = "default" + Descriptor item #13: + Key = "bgColorType" + OSType key = "enum" + Type = "ESliceBGColorType" + Enum = "None" + Descriptor item #14: + Key = "topOutset" + OSType key = "long" + Value = 0 + Descriptor item #15: + Key = "leftOutset" + OSType key = "long" + Value = 0 + Descriptor item #16: + Key = "bottomOutset" + OSType key = "long" + Value = 0 + Descriptor item #17: + Key = "rightOutset" + OSType key = "long" + Value = 0 + ----- + ----- + ----- + ----- + 8BIM: [0x0428] Name="" Len=[0x000C] DefinedName="Pixel Aspect Ratio" + Version = 2 + X/Y Ratio = 1.00000 + 8BIM: [0x0414] Name="" Len=[0x0004] DefinedName="Document-specific IDs seed number" + Base value = 1 + 8BIM: [0x040C] Name="" Len=[0x0922] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 107 pixels + Height of thumbnail = 160 pixels + Widthbytes = 324 bytes + Total size = 51840 bytes + Size after compression = 2310 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x000016FA + 8BIM: [0x0421] Name="" Len=[0x0055] DefinedName="Version Info" + Version = 1 + hasRealMergedData = 1 + Writer name = "Adobe Photoshop" + Reader name = "Adobe Photoshop CS6" + File version = 1 + 8BIM: [0x0406] Name="" Len=[0x0007] DefinedName="JPEG quality" + Photoshop Save As Quality = 7 + Photoshop Save Format = "Standard" + Photoshop Save Progressive Scans = "3 Scans" + ??? = 1 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00002076 + Length = 3752 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00002F20 + Length = 3160 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3144 bytes + Preferred CMM Type : 'Lino' (0x4C696E6F) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1998-02-09 06:49:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Microsoft Corporation ('MSFT' (0x4D534654)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'IEC ' (0x49454320) + Device Model : 'sRGB' (0x73524742) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'HP ' (0x48502020) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00003B7A + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00003B8A + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 10 7 7 10 15 18 20 17 + DQT, Row #1: 7 8 8 10 13 16 12 12 + DQT, Row #2: 7 8 8 10 16 12 12 12 + DQT, Row #3: 10 10 10 18 12 12 12 12 + DQT, Row #4: 15 13 16 12 12 12 12 12 + DQT, Row #5: 18 16 12 12 12 12 12 12 + DQT, Row #6: 20 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 83.48 (scaling=33.04 variance=462.13) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 11 12 21 34 20 20 17 17 + DQT, Row #1: 12 19 24 14 14 12 12 12 + DQT, Row #2: 21 24 14 14 12 12 12 12 + DQT, Row #3: 34 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 87.98 (scaling=24.05 variance=592.80) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00003C10 + Frame header length = 17 + Precision = 8 + Number of Lines = 700 + Samples per Line = 467 + Image Size = 467 x 700 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00003C23 + Length = 4 + interval = 59 + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003C29 + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 04 05 03 02 06 01 00 + Codes of length 04 bits (001 total): 07 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 04 05 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 11 04 00 + Codes of length 05 bits (003 total): 05 21 12 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 51 06 13 61 + Codes of length 08 bits (002 total): 22 71 + Codes of length 09 bits (006 total): 81 14 32 91 A1 07 + Codes of length 10 bits (007 total): 15 B1 42 23 C1 52 D1 + Codes of length 11 bits (003 total): E1 33 16 + Codes of length 12 bits (004 total): 62 F0 24 72 + Codes of length 13 bits (002 total): 82 F1 + Codes of length 14 bits (006 total): 25 43 34 53 92 A2 + Codes of length 15 bits (002 total): B2 63 + Codes of length 16 bits (115 total): 73 C2 35 44 27 93 A3 B3 36 17 54 64 74 C3 D2 E2 + 08 26 83 09 0A 18 19 84 94 45 46 A4 B4 56 D3 55 + 28 1A F2 E3 F3 C4 D4 E4 F4 65 75 85 95 A5 B5 C5 + D5 E5 F5 66 76 86 96 A6 B6 C6 D6 E6 F6 37 47 57 + 67 77 87 97 A7 B7 C7 D7 E7 F7 38 48 58 68 78 88 + 98 A8 B8 C8 D8 E8 F8 29 39 49 59 69 79 89 99 A9 + B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA + DA EA FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (002 total): 04 21 + Codes of length 06 bits (003 total): 12 31 41 + Codes of length 07 bits (005 total): 05 51 13 61 22 + Codes of length 08 bits (005 total): 06 71 81 91 32 + Codes of length 09 bits (004 total): A1 B1 F0 14 + Codes of length 10 bits (005 total): C1 D1 E1 23 42 + Codes of length 11 bits (006 total): 15 52 62 72 F1 33 + Codes of length 12 bits (004 total): 24 34 43 82 + Codes of length 13 bits (008 total): 16 92 53 25 A2 63 B2 C2 + Codes of length 14 bits (003 total): 07 73 D2 + Codes of length 15 bits (003 total): 35 E2 44 + Codes of length 16 bits (109 total): 83 17 54 93 08 09 0A 18 19 26 36 45 1A 27 64 74 + 55 37 F2 A3 B3 C3 28 29 D3 E3 F3 84 94 A4 B4 C4 + D4 E4 F4 65 75 85 95 A5 B5 C5 D5 E5 F5 46 56 66 + 76 86 96 A6 B6 C6 D6 E6 F6 47 57 67 77 87 97 A7 + B7 C7 D7 E7 F7 38 48 58 68 78 88 98 A8 B8 C8 D8 + E8 F8 39 49 59 69 79 89 99 A9 B9 C9 D9 E9 F9 2A + 3A 4A 5A 6A 7A 8A 9A AA BA CA DA EA FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003DCD + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00003DDB + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00009013.0 + + Compression stats: + Compression Ratio: 46.60:1 + Bits per pixel: 0.52:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 4910 ( 95%) + # codes of length 04 bits: 280 ( 5%) + # codes of length 05 bits: 2 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 9997 ( 96%) + # codes of length 03 bits: 335 ( 3%) + # codes of length 04 bits: 52 ( 1%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 5649 ( 33%) + # codes of length 03 bits: 1560 ( 9%) + # codes of length 04 bits: 6758 ( 39%) + # codes of length 05 bits: 1189 ( 7%) + # codes of length 06 bits: 349 ( 2%) + # codes of length 07 bits: 488 ( 3%) + # codes of length 08 bits: 255 ( 1%) + # codes of length 09 bits: 351 ( 2%) + # codes of length 10 bits: 254 ( 1%) + # codes of length 11 bits: 70 ( 0%) + # codes of length 12 bits: 76 ( 0%) + # codes of length 13 bits: 14 ( 0%) + # codes of length 14 bits: 115 ( 1%) + # codes of length 15 bits: 41 ( 0%) + # codes of length 16 bits: 88 ( 1%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 10917 ( 93%) + # codes of length 03 bits: 435 ( 4%) + # codes of length 04 bits: 77 ( 1%) + # codes of length 05 bits: 75 ( 1%) + # codes of length 06 bits: 121 ( 1%) + # codes of length 07 bits: 47 ( 0%) + # codes of length 08 bits: 36 ( 0%) + # codes of length 09 bits: 5 ( 0%) + # codes of length 10 bits: 15 ( 0%) + # codes of length 11 bits: 39 ( 0%) + # codes of length 12 bits: 11 ( 0%) + # codes of length 13 bits: 3 ( 0%) + # codes of length 14 bits: 2 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[222] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1020, 0, 0] RGB=[255,255,255] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 87 + Next position in scan buffer: Offset 0x00009012.5 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00009013 + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000546 + Length: 0x00000906 (2310) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: APP13 + Length = 12 + + * Embedded Thumb Marker: APP14 + Length = 14 + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 12 8 8 12 17 21 24 17 + DQT, Row #1: 8 9 9 11 15 19 12 12 + DQT, Row #2: 8 9 10 12 19 12 12 12 + DQT, Row #3: 12 11 12 21 12 12 12 12 + DQT, Row #4: 17 15 19 12 12 12 12 12 + DQT, Row #5: 21 19 12 12 12 12 12 12 + DQT, Row #6: 24 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 13 11 13 16 20 20 17 17 + DQT, Row #1: 11 14 14 14 14 12 12 12 + DQT, Row #2: 13 14 14 14 12 12 12 12 + DQT, Row #3: 16 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 160 + Samples per Line = 107 + Image Size = 107 x 160 + + * Embedded Thumb Marker: DRI + Length = 4 + + * Embedded Thumb Marker: DHT + Length = 319 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 1785 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01C2DDA29A1B5DCCD5E217CF9C558A62 + +*** Searching Compression Signatures *** + + Signature: 0165B3F1B409A4D8D5F2ADFFA970D3A5 + Signature (Rotated): 0165B3F1B409A4D8D5F2ADFFA970D3A5 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [Canon] [Canon EOS 70D] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CS6 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E885 ] [FINE ] Yes + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + + NOTE: Photoshop IRB detected + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt new file mode 100644 index 0000000000..48760626be --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt @@ -0,0 +1,435 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\issue750-exif-tranform.jpg] + Filesize: [5587341] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 8272 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x000A + [Make ] = "Canon" + [Model ] = "Canon EOS 500D" + [Orientation ] = 1 = Row 0: top, Col 0: left + [DateTime ] = "2017:12:06 15:48:51" + [Artist ] = "" + [YCbCrPositioning ] = Co-sited + [Copyright ] = "" + [ExifOffset ] = @ 0x00B0 + [GPSOffset ] = @ 0x2034 + [XPAuthor ] = "??" + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000CE + Dir Length = 0x0020 + [ExposureTime ] = 1/160 s + [FNumber ] = F9.0 + [ExposureProgram ] = Normal program + [ISOSpeedRatings ] = 3200 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2017:12:06 15:48:51" + [DateTimeDigitized ] = "2017:12:06 15:48:51" + [ComponentsConfiguration ] = [Y Cb Cr .] + [ShutterSpeedValue ] = 483328/65536 + [ApertureValue ] = 417792/65536 + [ExposureBiasValue ] = 1.00 eV + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 24 mm + [MakerNote ] = @ 0x028E + [UserComment ] = "" + [SubSecTime ] = "80" + [SubSecTimeOriginal ] = "80" + [SubSecTimeDigitized ] = "80" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 4752 + [ExifImageHeight ] = 3168 + [ExifInteroperabilityOffset ] = @ 0x2010 + [FocalPlaneXResolution ] = 4752000/894 + [FocalPlaneYResolution ] = 3168000/593 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + + EXIF MakerIFD @ Absolute 0x000002AC + Makernote decode option not enabled. + + EXIF GPSIFD @ Absolute 0x00002052 + Dir Length = 0x0001 + [GPSVersionID ] = 2.2.0.0 + + EXIF InteropIFD @ Absolute 0x0000202E + Dir Length = 0x0001 + [InteroperabilityVersion ] = 01.00 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002066 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 2 3 4 + DQT, Row #1: 1 1 1 1 2 3 4 3 + DQT, Row #2: 1 1 1 1 2 3 4 3 + DQT, Row #3: 1 1 1 2 3 5 5 4 + DQT, Row #4: 1 1 2 3 4 7 6 5 + DQT, Row #5: 1 2 3 4 5 6 7 6 + DQT, Row #6: 3 4 5 5 6 7 7 6 + DQT, Row #7: 4 6 6 6 7 6 6 6 + Approx quality factor = 96.95 (scaling=6.11 variance=1.09) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000020AB + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 3 6 6 6 6 + DQT, Row #1: 1 1 2 4 6 6 6 6 + DQT, Row #2: 1 2 3 6 6 6 6 6 + DQT, Row #3: 3 4 6 6 6 6 6 6 + DQT, Row #4: 6 6 6 6 6 6 6 6 + DQT, Row #5: 6 6 6 6 6 6 6 6 + DQT, Row #6: 6 6 6 6 6 6 6 6 + DQT, Row #7: 6 6 6 6 6 6 6 6 + Approx quality factor = 96.99 (scaling=6.01 variance=0.24) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000020F0 + Frame header length = 17 + Precision = 8 + Number of Lines = 3168 + Samples per Line = 4752 + Image Size = 4752 x 3168 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002103 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002124 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000021DB + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000021FC + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000022B3 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000022C1 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0055418B.0 + + Compression stats: + Compression Ratio: 8.10:1 + Bits per pixel: 2.96:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 7852 ( 3%) + # codes of length 03 bits: 194801 ( 83%) + # codes of length 04 bits: 18114 ( 8%) + # codes of length 05 bits: 9703 ( 4%) + # codes of length 06 bits: 3623 ( 2%) + # codes of length 07 bits: 941 ( 0%) + # codes of length 08 bits: 188 ( 0%) + # codes of length 09 bits: 2 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 53609 ( 46%) + # codes of length 03 bits: 36337 ( 31%) + # codes of length 04 bits: 20089 ( 17%) + # codes of length 05 bits: 4404 ( 4%) + # codes of length 06 bits: 2062 ( 2%) + # codes of length 07 bits: 903 ( 1%) + # codes of length 08 bits: 206 ( 0%) + # codes of length 09 bits: 2 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 3801677 ( 49%) + # codes of length 03 bits: 1263986 ( 16%) + # codes of length 04 bits: 1288745 ( 17%) + # codes of length 05 bits: 606891 ( 8%) + # codes of length 06 bits: 282047 ( 4%) + # codes of length 07 bits: 273734 ( 4%) + # codes of length 08 bits: 85749 ( 1%) + # codes of length 09 bits: 90483 ( 1%) + # codes of length 10 bits: 39213 ( 1%) + # codes of length 11 bits: 19089 ( 0%) + # codes of length 12 bits: 6439 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 136 ( 0%) + # codes of length 16 bits: 7545 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 309037 ( 51%) + # codes of length 03 bits: 124353 ( 21%) + # codes of length 04 bits: 87742 ( 14%) + # codes of length 05 bits: 43060 ( 7%) + # codes of length 06 bits: 28928 ( 5%) + # codes of length 07 bits: 2442 ( 0%) + # codes of length 08 bits: 8544 ( 1%) + # codes of length 09 bits: 1150 ( 0%) + # codes of length 10 bits: 376 ( 0%) + # codes of length 11 bits: 126 ( 0%) + # codes of length 12 bits: 30 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 50 ( 0%) + # codes of length 15 bits: 24 ( 0%) + # codes of length 16 bits: 4 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[215] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1016, -3, 3] RGB=[255,255,253] @ MCU[ 92, 26] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0055418A.7 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0055418B + + +*** Searching Compression Signatures *** + + Signature: 010564D93F295ADB889B91604DC82EE1 + Signature (Rotated): 014302FE54745F4DBB58A0D51CDC66BD + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [Canon] [Canon EOS 500D] + EXIF Makernotes: OK + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Leica Camera AG ] [M8 Digital Camera ] [ ] No + CAM:[Leica Camera AG ] [M8 Digital Camera ] [ ] No + CAM:[Leica Camera AG ] [M8 Digital Camera ] [ ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5400 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C40Z,D40Z ] [ ] No + CAM:[Samsung Techwin ] [Digimax V50/a5 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [Pro 815 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV 7, NV 7 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV10, NV10 ] [ ] No + CAM:[SONY ] [CYBERSHOT ] [ ] No + CAM:[SONY ] [DSC-H1 ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H5 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-L1 ] [ ] No + CAM:[SONY ] [DSC-N2 ] [ ] No + CAM:[SONY ] [DSC-P150 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-R1 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-V1 ] [ ] No + CAM:[SONY ] [DSC-V3 ] [ ] No + CAM:[SONY ] [DSC-W35 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[IJG Library ] [097 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [097 ] + SW :[IrfanView ] [097 ] + SW :[idImager ] [097 ] + SW :[FastStone Image Viewer ] [097 ] + SW :[NeatImage ] [097 ] + SW :[Paint.NET ] [097 ] + SW :[Photomatix ] [097 ] + SW :[XnView ] [097 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 4 - Uncertain if processed or original + While the EXIF fields indicate original, no compression signatures + in the current database were found matching this make/model + + Appears to be new signature for known camera. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt new file mode 100644 index 0000000000..b6a1fe8094 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt @@ -0,0 +1,452 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\BadEofProgressive.jpg] + Filesize: [67503] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000014 + Length = 124 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x005F] DefinedName="IPTC-NAA record" + IPTC [002:040] Special Instructions = "FBMD2300098903000068210000c735000008450000e88e0000fab00000c6cd000002f80000191a0100653f0100" + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000092 + Length = 540 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 524 bytes + Preferred CMM Type : 'lcms' (0x6C636D73) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2012-01-25 03:41:57 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'lcms' (0x6C636D73) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000002B0 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 10 16 20 24 + DQT, Row #1: 5 5 6 8 10 23 24 22 + DQT, Row #2: 6 5 6 10 16 23 28 22 + DQT, Row #3: 6 7 9 12 20 35 32 25 + DQT, Row #4: 7 9 15 22 27 44 41 31 + DQT, Row #5: 10 14 22 26 32 42 45 37 + DQT, Row #6: 20 26 31 35 41 48 48 40 + DQT, Row #7: 29 37 38 39 45 40 41 40 + Approx quality factor = 79.94 (scaling=40.12 variance=1.43) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000002F5 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 10 19 40 40 40 40 + DQT, Row #1: 7 8 10 26 40 40 40 40 + DQT, Row #2: 10 10 22 40 40 40 40 40 + DQT, Row #3: 19 26 40 40 40 40 40 40 + DQT, Row #4: 40 40 40 40 40 40 40 40 + DQT, Row #5: 40 40 40 40 40 40 40 40 + DQT, Row #6: 40 40 40 40 40 40 40 40 + DQT, Row #7: 40 40 40 40 40 40 40 40 + Approx quality factor = 79.87 (scaling=40.26 variance=0.36) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000033A + Frame header length = 17 + Precision = 8 + Number of Lines = 640 + Samples per Line = 640 + Image Size = 640 x 640 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000034D + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 01 02 03 04 05 06 07 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000036C + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (003 total): 00 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000389 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),0(AC) + Component[3]: selector=0x02, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002127 + Huffman table length = 63 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (004 total): 00 02 03 11 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (002 total): 05 41 + Codes of length 07 bits (003 total): 13 22 51 + Codes of length 08 bits (004 total): 10 32 61 A1 + Codes of length 09 bits (007 total): 14 20 71 81 91 B1 F0 + Codes of length 10 bits (007 total): 06 23 42 52 C1 D1 E1 + Codes of length 11 bits (002 total): 15 30 + Codes of length 12 bits (005 total): 16 24 33 34 62 + Codes of length 13 bits (005 total): 25 40 50 72 F1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 044 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002168 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003588 + Huffman table length = 61 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (003 total): 04 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 05 10 13 51 + Codes of length 08 bits (003 total): 14 20 22 + Codes of length 09 bits (005 total): 32 42 61 71 91 + Codes of length 10 bits (007 total): 15 23 33 81 A1 B1 C1 + Codes of length 11 bits (003 total): 06 30 D1 + Codes of length 12 bits (002 total): E1 F0 + Codes of length 13 bits (007 total): 16 24 34 40 43 50 52 + Codes of length 14 bits (001 total): 62 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 042 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000035C7 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000044BF + Huffman table length = 71 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (004 total): 13 22 41 51 + Codes of length 07 bits (007 total): 05 10 20 32 61 71 81 + Codes of length 08 bits (005 total): 14 23 42 52 91 + Codes of length 09 bits (005 total): 30 33 62 72 A1 + Codes of length 10 bits (007 total): 15 34 43 53 82 92 B1 + Codes of length 11 bits (003 total): 06 24 40 + Codes of length 12 bits (004 total): 44 A2 C1 D1 + Codes of length 13 bits (001 total): E1 + Codes of length 14 bits (004 total): 25 35 50 F0 + Codes of length 15 bits (003 total): 54 63 73 + Codes of length 16 bits (000 total): + Total number of codes: 052 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00004508 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008EC5 + Huffman table length = 33 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 10 21 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (001 total): 51 + Codes of length 08 bits (001 total): 20 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (001 total): 71 + Codes of length 11 bits (001 total): 30 + Codes of length 12 bits (001 total): 81 + Codes of length 13 bits (001 total): 40 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 014 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008EE8 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 10 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000B0CE + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (006 total): 10 41 51 61 71 91 + Codes of length 06 bits (002 total): 20 81 + Codes of length 07 bits (001 total): 30 + Codes of length 08 bits (005 total): 40 A1 B1 C1 F0 + Codes of length 09 bits (001 total): D1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): 50 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000B0FA + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 11 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000CDA4 + Huffman table length = 32 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (001 total): 10 + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (001 total): 51 + Codes of length 09 bits (001 total): 20 + Codes of length 10 bits (001 total): 61 + Codes of length 11 bits (001 total): 71 + Codes of length 12 bits (001 total): 81 + Codes of length 13 bits (001 total): 91 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000CDC6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 10 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000F7DF + Huffman table length = 33 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 10 41 + Codes of length 06 bits (003 total): 51 61 71 + Codes of length 07 bits (001 total): 20 + Codes of length 08 bits (001 total): 81 + Codes of length 09 bits (001 total): 30 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 014 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000F802 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 11 .. 19 + Successive approximation = 0x10 +ERROR: Ran out of buffer before EOI during phase 1 of Scan decode @ 0x000107B0 + + NOTE: Scan parsing doesn't support this SOF mode. + +ERROR: Early EOF - file may be missing EOI + +*** Searching Compression Signatures *** + + Signature: 01DC499064BA9264D591FDE9071DFD89 + Signature (Rotated): 0175BAF3251040E0EFB2930B73328E7F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C40Z,D40Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + SW :[Apple ImageIO.framework ] [050 (Normal) ] + SW :[IJG Library ] [080 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [080 ] + SW :[IrfanView ] [080 ] + SW :[idImager ] [080 ] + SW :[FastStone Image Viewer ] [080 ] + SW :[NeatImage ] [080 ] + SW :[Paint.NET ] [080 ] + SW :[Photomatix ] [080 ] + SW :[XnView ] [080 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt new file mode 100644 index 0000000000..397343c5e5 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt @@ -0,0 +1,535 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\ExifUndefType.jpg] + Filesize: [6582] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 804 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 86020000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x000002A4 + Dir Length = 0x000C + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CS4 Windows" + [DateTime ] = "2014:03:28 16:44:10" + [WhitePoint ] = 0/1000000, 0/1000000 + [PrimChromaticities ] = 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000 + [YCbCrCoefficients ] = 0/1000000, 0/1000000, 0/1000000 + [YCbCrPositioning ] = 0 + [ReferenceBlackWhite ] = 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000 + [ExifOffset ] = @ 0x0138 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000156 + Dir Length = 0x001B + [ExposureTime ] = 0/1000000 s + [FNumber ] = F0.0 + [ExposureProgram ] = Not defined + [ISOSpeedRatings ] = 0, 0 + [ExifVersion ] = 12.20 + [CompressedBitsPerPixel ] = 0/1000000 + [ShutterSpeedValue ] = 0/1000000 + [ApertureValue ] = 0/1000000 + [BrightnessValue ] = 0/1000000 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 0/1000000 + [SubjectDistance ] = 0/1000000 + [MeteringMode ] = Unknown + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 0 mm + [FlashPixVersion ] = + [ColorSpace ] = sRGB + [ExifImageWidth ] = 850 + [ExifImageHeight ] = 638 + [FocalPlaneXResolution ] = 0/1000000 + [FocalPlaneYResolution ] = 0/1000000 + [FocalPlaneResolutionUnit ] = 0 + [ExposureIndex ] = 0/1000000 + [SensingMethod ] = 0 + [FileSource ] = 0 + [SceneType ] = 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000033A + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000037F + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x000003C4 + Frame header length = 17 + Precision = 8 + Number of Lines = 165 + Samples per Line = 220 + Image Size = 220 x 165 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000003D7 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 03 07 + Codes of length 04 bits (003 total): 02 04 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 01 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000003F5 + Huffman table length = 22 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (000 total): + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 003 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000040D + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000581 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (006 total): 00 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 11 15 16 + Codes of length 06 bits (004 total): 12 13 14 21 + Codes of length 07 bits (002 total): 07 10 + Codes of length 08 bits (002 total): 22 40 + Codes of length 09 bits (003 total): 17 30 60 + Codes of length 10 bits (001 total): 24 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000005AC + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000883 + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 11 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 01 10 + Codes of length 05 bits (003 total): 20 30 40 + Codes of length 06 bits (001 total): 50 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000008A0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000008BF + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (001 total): 01 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 10 21 30 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 20 40 50 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000008DD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000905 + Huffman table length = 65 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (004 total): 00 01 02 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (004 total): 12 21 31 34 + Codes of length 06 bits (008 total): 13 32 33 35 91 92 93 D2 + Codes of length 07 bits (009 total): 05 10 14 22 41 51 71 A1 D1 + Codes of length 08 bits (010 total): 20 23 40 42 52 61 81 A2 A3 B1 + Codes of length 09 bits (007 total): 15 24 60 62 72 E1 E2 + Codes of length 10 bits (001 total): 30 + Codes of length 11 bits (001 total): B2 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 046 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000948 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000E49 + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (004 total): 51 61 71 D1 + Codes of length 07 bits (006 total): 81 91 A1 C1 F0 F1 + Codes of length 08 bits (002 total): 40 B1 + Codes of length 09 bits (003 total): 10 20 60 + Codes of length 10 bits (001 total): 30 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E75 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001266 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000012E8 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (001 total): 10 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 30 51 + Codes of length 06 bits (003 total): 21 40 50 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001306 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000133E + Huffman table length = 30 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 30 51 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 20 61 + Codes of length 07 bits (003 total): 21 40 50 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000135E + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000139C + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (003 total): 41 51 61 + Codes of length 07 bits (003 total): 71 81 B1 + Codes of length 08 bits (003 total): 91 A1 D1 + Codes of length 09 bits (004 total): 10 40 E1 F0 + Codes of length 10 bits (003 total): 20 C1 F1 + Codes of length 11 bits (001 total): 60 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000013C8 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000019B4 + + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CS4 Windows] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] Yes + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + Appears to be new signature for known software. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt new file mode 100644 index 0000000000..445e80a7e7 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt @@ -0,0 +1,459 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Festzug.jpg] + Filesize: [49977] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 229 x 229 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 131 + ---- + Precision=16 bits + Destination ID=0 (Luminance) + DQT, Row #0: 53 37 33 53 80 133 170 203 + DQT, Row #1: 40 40 47 63 87 193 200 183 + DQT, Row #2: 47 43 53 80 133 190 230 186 + DQT, Row #3: 47 57 73 97 170 290 266 206 + DQT, Row #4: 60 73 123 186 226 363 343 256 + DQT, Row #5: 80 117 183 213 270 346 376 306 + DQT, Row #6: 163 213 260 290 343 403 400 336 + DQT, Row #7: 240 306 316 326 373 333 343 330 + Approx quality factor = 15.01 (scaling=333.00 variance=1.25) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000099 + Table length = 131 + ---- + Precision=16 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 57 60 80 157 330 330 330 330 + DQT, Row #1: 60 70 87 220 330 330 330 330 + DQT, Row #2: 80 87 186 330 330 330 330 330 + DQT, Row #3: 157 220 330 330 330 330 330 330 + DQT, Row #4: 330 330 330 330 330 330 330 330 + DQT, Row #5: 330 330 330 330 330 330 330 330 + DQT, Row #6: 330 330 330 330 330 330 330 330 + DQT, Row #7: 330 330 330 330 330 330 330 330 + Approx quality factor = 15.00 (scaling=333.41 variance=0.14) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000011E + Frame header length = 17 + Precision = 8 + Number of Lines = 1071 + Samples per Line = 1443 + Image Size = 1443 x 1071 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000131 + Huffman table length = 25 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000014C + Huffman table length = 22 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (000 total): + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 003 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000164 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000028E0 + Huffman table length = 38 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (004 total): 02 10 20 30 + Codes of length 05 bits (003 total): 12 31 40 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 21 41 50 + Codes of length 08 bits (001 total): 60 + Codes of length 09 bits (001 total): 03 + Codes of length 10 bits (000 total): + Codes of length 11 bits (003 total): 22 32 42 + Codes of length 12 bits (001 total): 13 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002908 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003D97 + Huffman table length = 29 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 00 10 11 + Codes of length 04 bits (001 total): 20 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 30 60 + Codes of length 07 bits (003 total): 80 90 C0 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003DB6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003DE1 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 10 11 + Codes of length 04 bits (003 total): 00 20 60 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 80 90 C0 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003DFF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003E21 + Huffman table length = 23 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 21 + Codes of length 02 bits (001 total): D0 + Codes of length 03 bits (001 total): A0 + Codes of length 04 bits (001 total): B0 + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 004 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003E3A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003E4C + Huffman table length = 36 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 10 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (003 total): 20 30 41 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 40 50 51 + Codes of length 08 bits (001 total): 61 + Codes of length 09 bits (001 total): 60 + Codes of length 10 bits (001 total): 71 + Codes of length 11 bits (001 total): 81 + Codes of length 12 bits (001 total): B1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 017 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003E72 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006325 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007512 + Huffman table length = 30 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 21 60 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 20 41 80 + Codes of length 08 bits (001 total): C0 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007532 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000075CE + Huffman table length = 30 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (001 total): 10 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 21 31 60 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 20 80 C0 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000075EE + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007676 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (002 total): 10 41 + Codes of length 07 bits (002 total): 20 51 + Codes of length 08 bits (002 total): 30 61 + Codes of length 09 bits (003 total): 40 50 71 + Codes of length 10 bits (000 total): + Codes of length 11 bits (003 total): 60 81 91 + Codes of length 12 bits (001 total): A1 + Codes of length 13 bits (001 total): B1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (002 total): C1 D1 + Codes of length 16 bits (003 total): E1 F0 F1 + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000076A3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000C337 + + +*** Searching Compression Signatures *** + + Signature: 0105A3D95D2D36DE9351313E30D8E945 + Signature (Rotated): 013C3A43642D2E8325A76C3818B3C324 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [015 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [015 ] + SW :[IrfanView ] [015 ] + SW :[idImager ] [015 ] + SW :[FastStone Image Viewer ] [015 ] + SW :[NeatImage ] [015 ] + SW :[Paint.NET ] [015 ] + SW :[Photomatix ] [015 ] + SW :[XnView ] [015 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt new file mode 100644 index 0000000000..6f20fc1ee8 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt @@ -0,0 +1,525 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\fb.jpg] + Filesize: [15787] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000014 + Comment length = 4 + Comment=*. + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000001A + Length = 540 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 524 bytes + Preferred CMM Type : 'lcms' (0x6C636D73) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2012-01-25 03:41:57 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'lcms' (0x6C636D73) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000238 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000027D + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x000002C2 + Frame header length = 17 + Precision = 8 + Number of Lines = 336 + Samples per Line = 276 + Image Size = 276 x 336 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002D5 + Huffman table length = 27 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 00 02 03 05 06 + Codes of length 04 bits (001 total): 01 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002F2 + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 03 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000030C + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 03 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000326 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000935 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (002 total): 01 04 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (002 total): 11 12 + Codes of length 06 bits (006 total): 05 10 13 20 31 32 + Codes of length 07 bits (002 total): 21 33 + Codes of length 08 bits (002 total): 14 22 + Codes of length 09 bits (002 total): 34 41 + Codes of length 10 bits (003 total): 15 23 30 + Codes of length 11 bits (001 total): 24 + Codes of length 12 bits (001 total): 42 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000962 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000012EE + Huffman table length = 39 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 10 + Codes of length 05 bits (004 total): 03 20 21 31 + Codes of length 06 bits (001 total): 12 + Codes of length 07 bits (004 total): 13 30 41 51 + Codes of length 08 bits (001 total): 22 + Codes of length 09 bits (005 total): 32 40 42 50 61 + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001317 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000142A + Huffman table length = 36 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 10 + Codes of length 05 bits (004 total): 03 20 21 31 + Codes of length 06 bits (002 total): 12 30 + Codes of length 07 bits (002 total): 13 41 + Codes of length 08 bits (003 total): 22 40 51 + Codes of length 09 bits (001 total): 50 + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 017 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001450 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000155A + Huffman table length = 51 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 02 + Codes of length 04 bits (003 total): 03 10 11 + Codes of length 05 bits (006 total): 12 20 21 31 41 51 + Codes of length 06 bits (005 total): 22 32 61 71 81 + Codes of length 07 bits (002 total): 13 30 + Codes of length 08 bits (005 total): 04 33 42 72 91 + Codes of length 09 bits (004 total): 14 52 62 A1 + Codes of length 10 bits (003 total): 23 82 B1 + Codes of length 11 bits (001 total): 43 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000158F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001D3E + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (001 total): 31 + Codes of length 05 bits (003 total): 10 41 51 + Codes of length 06 bits (004 total): 20 61 71 A1 + Codes of length 07 bits (002 total): 81 91 + Codes of length 08 bits (002 total): B1 F0 + Codes of length 09 bits (003 total): 30 C1 D1 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001D68 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000028B9 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000029E4 + Huffman table length = 32 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 10 21 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 20 41 51 + Codes of length 08 bits (001 total): 30 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (001 total): 50 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002A06 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002B55 + Huffman table length = 32 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (003 total): 10 21 31 + Codes of length 05 bits (001 total): 20 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 30 51 61 + Codes of length 09 bits (001 total): 71 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002B77 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002CEA + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (003 total): 31 41 51 + Codes of length 06 bits (003 total): 10 61 71 + Codes of length 07 bits (004 total): 81 91 A1 B1 + Codes of length 08 bits (003 total): 20 C1 F0 + Codes of length 09 bits (001 total): D1 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002D14 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00003DA9 + + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt new file mode 100644 index 0000000000..f38a115328 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt @@ -0,0 +1,468 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\progress.jpg] + Filesize: [44884] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 486 + Samples per Line = 341 + Image Size = 341 x 486 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 01 02 03 05 06 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CF + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 00 01 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000EB + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000CCC + Huffman table length = 45 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 00 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (001 total): 12 + Codes of length 06 bits (003 total): 05 13 21 + Codes of length 07 bits (003 total): 10 22 31 + Codes of length 08 bits (004 total): 14 20 32 41 + Codes of length 09 bits (002 total): 06 23 + Codes of length 10 bits (002 total): 30 33 + Codes of length 11 bits (003 total): 15 24 42 + Codes of length 12 bits (001 total): 34 + Codes of length 13 bits (001 total): 43 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000CFB + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000020DC + Huffman table length = 46 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (001 total): 11 + Codes of length 05 bits (004 total): 04 10 21 31 + Codes of length 06 bits (001 total): 12 + Codes of length 07 bits (003 total): 13 20 41 + Codes of length 08 bits (003 total): 05 22 51 + Codes of length 09 bits (003 total): 23 32 61 + Codes of length 10 bits (005 total): 14 30 33 42 71 + Codes of length 11 bits (000 total): + Codes of length 12 bits (003 total): 15 52 91 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 027 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000210C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002604 + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (002 total): 03 10 + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (002 total): 12 20 + Codes of length 07 bits (001 total): 13 + Codes of length 08 bits (004 total): 04 22 41 61 + Codes of length 09 bits (002 total): 42 51 + Codes of length 10 bits (002 total): 14 32 + Codes of length 11 bits (003 total): 33 71 F0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000262F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000029A7 + Huffman table length = 61 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 11 + Codes of length 04 bits (003 total): 03 12 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (005 total): 10 22 41 51 61 + Codes of length 07 bits (006 total): 04 13 20 32 71 81 + Codes of length 08 bits (005 total): 23 30 42 52 91 + Codes of length 09 bits (002 total): A1 B1 + Codes of length 10 bits (004 total): 62 72 C1 F0 + Codes of length 11 bits (006 total): 14 33 40 82 D1 E1 + Codes of length 12 bits (001 total): 24 + Codes of length 13 bits (005 total): 05 43 53 73 F1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 042 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000029E6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003FF3 + Huffman table length = 39 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (003 total): 71 81 91 + Codes of length 08 bits (004 total): 10 A1 B1 C1 + Codes of length 09 bits (003 total): D1 E1 F0 + Codes of length 10 bits (001 total): 20 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000401C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006299 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000064A9 + Huffman table length = 39 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (003 total): 31 41 51 + Codes of length 06 bits (003 total): 10 61 71 + Codes of length 07 bits (004 total): 81 91 D1 F0 + Codes of length 08 bits (003 total): A1 B1 E1 + Codes of length 09 bits (001 total): C1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000064D2 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006ACB + Huffman table length = 38 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (002 total): 10 51 + Codes of length 08 bits (001 total): 61 + Codes of length 09 bits (003 total): 91 D1 F0 + Codes of length 10 bits (005 total): 71 81 A1 B1 C1 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (001 total): E1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006AF3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006F95 + Huffman table length = 38 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (002 total): 71 81 + Codes of length 08 bits (002 total): 91 A1 + Codes of length 09 bits (002 total): B1 F0 + Codes of length 10 bits (003 total): C1 D1 E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (001 total): 10 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006FBD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000AF52 + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + From cfb9c61b6cfdbdfb41d7c10e2e6ca43f8dba8300 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Sat, 3 Nov 2018 19:24:30 -0500 Subject: [PATCH 141/238] 762: added AoT method to pre-seed dithering engine --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index b226201082..2c5496f528 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -5,6 +5,8 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp @@ -54,5 +56,17 @@ namespace SixLabors.ImageSharp var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); test.AotGetPalette(); } + + /// + /// This method pre-seeds the default FloydSteinbergDiffuser in the AoT compiler for iOS. + /// + /// The pixel format. + public static void AotCompileDithering() + where TPixel : struct, IPixel + { + var test = new FloydSteinbergDiffuser(); + TPixel pixel = default; + test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); + } } } From 78070dcc8928561f21f3aa5d59bdcc808ac951ec Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Sat, 3 Nov 2018 19:36:47 -0500 Subject: [PATCH 142/238] 762: added AoT method to pre-seed WuQuantizer --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 14 +++++++++++++- .../Quantization/WuFrameQuantizer{TPixel}.cs | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 2c5496f528..f1c2ae5fb5 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -58,7 +58,19 @@ namespace SixLabors.ImageSharp } /// - /// This method pre-seeds the default FloydSteinbergDiffuser in the AoT compiler for iOS. + /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. + /// + /// The pixel format. + public static void AotCompileWuQuantizer() + where TPixel : struct, IPixel + { + var test = new WuFrameQuantizer(new WuQuantizer(false)); + test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. /// /// The pixel format. public static void AotCompileDithering() diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 43d22597df..44df226cfd 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -173,6 +173,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + internal TPixel[] AotGetPalette() => this.GetPalette(); + /// protected override TPixel[] GetPalette() { From 8c6903873bc4c48ddc2e933c82a73e2510aaf9f4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 01:53:21 +0100 Subject: [PATCH 143/238] improved benchmarks + more benchmark results --- .../Common/Helpers/InliningOptions.cs | 2 +- .../Codecs/Jpeg/DecodeJpeg.cs | 89 ------------- .../Codecs/Jpeg/DecodeJpegMultiple.cs | 18 ++- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 125 ++++++++++++++++++ .../Codecs/Jpeg/LoadResizeSave.cs | 2 +- .../Codecs/Jpeg/LoadResizeSave_MultiImage.cs | 88 ++++++++++++ .../Codecs/MultiImageBenchmarkBase.cs | 30 ++++- .../ProfilingBenchmarks/JpegBenchmarks.cs | 56 ++++---- tests/ImageSharp.Tests/TestImages.cs | 13 ++ 9 files changed, 294 insertions(+), 129 deletions(-) delete mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs create mode 100644 tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index ad85c4fc81..069a426d75 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// Uncomment this for verbose profiler results: +// Uncomment this for verbose profiler results. DO NOT PUSH TO MAIN! // #define PROFILING using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs deleted file mode 100644 index 57dcede88d..0000000000 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Drawing; -using System.IO; -using BenchmarkDotNet.Attributes; - -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Tests; -using CoreSize = SixLabors.Primitives.Size; -using SDImage = System.Drawing.Image; - -namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg -{ - [Config(typeof(Config.ShortClr))] - public class DecodeJpeg - { - private byte[] jpegBytes; - - private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); - - [Params(TestImages.Jpeg.Baseline.Jpeg420Exif - //, TestImages.Jpeg.Baseline.Calliphora - )] - public string TestImage { get; set; } - - [GlobalSetup] - public void ReadImages() - { - if (this.jpegBytes == null) - { - this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath); - } - } - - [Benchmark(Baseline = true, Description = "Decode Jpeg - System.Drawing")] - public Size JpegSystemDrawing() - { - using (var memoryStream = new MemoryStream(this.jpegBytes)) - { - using (var image = SDImage.FromStream(memoryStream)) - { - return image.Size; - } - } - } - - [Benchmark(Description = "Decode Jpeg - ImageSharp")] - public CoreSize JpegImageSharp() - { - using (var memoryStream = new MemoryStream(this.jpegBytes)) - { - using (var image = Image.Load(memoryStream, new JpegDecoder())) - { - return new CoreSize(image.Width, image.Height); - } - } - } - - // RESULTS (2018 October): - // - // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 - // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores - // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC - // .NET Core SDK=2.1.403 - // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT - // Job-MCUBGX : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 - // Job-TZIRPF : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT - // - // - // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| - // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.10 ms | 4.720 ms | 0.2667 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | - // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 57.77 ms | 4.626 ms | 0.2614 ms | 3.38 | 0.04 | 125.0000 | 566.01 KB | - // | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | - // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | - - // RESULTS (2018 November 1): - // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| - // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.59 ms | 4.611 ms | 0.2605 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | - // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 55.33 ms | 2.133 ms | 0.1205 ms | 3.15 | 0.04 | 125.0000 | 566.01 KB | - // | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.83 ms | 24.326 ms | 1.3745 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | - // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 44.93 ms | 3.088 ms | 0.1745 ms | 2.53 | 0.15 | 125.0000 | 529.96 KB | - } -} diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs index be0fe76b82..53459e3c45 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs @@ -2,23 +2,27 @@ // Licensed under the Apache License, Version 2.0. using System.Collections.Generic; + using BenchmarkDotNet.Attributes; + using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests; + using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { - [Config(typeof(Config.ShortClr))] + /// + /// An expensive Jpeg benchmark, running on a wide range of input images, showing aggregate results. + /// + [Config(typeof(MultiImageBenchmarkBase.Config))] public class DecodeJpegMultiple : MultiImageBenchmarkBase { - protected override IEnumerable InputImageSubfoldersOrFiles => new[] - { - "Jpg/baseline", - "Jpg/progressive", - }; + protected override IEnumerable InputImageSubfoldersOrFiles => TestImages.Jpeg.BenchmarkSuite; - protected override IEnumerable SearchPatterns => new[] { "*.jpg" }; + [Params(InputImageCategory.AllImages)] + public override InputImageCategory InputCategory { get; set; } [Benchmark(Description = "DecodeJpegMultiple - ImageSharp")] public void DecodeJpegImageSharp() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs new file mode 100644 index 0000000000..e161bca05b --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -0,0 +1,125 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Drawing; +using System.IO; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Jobs; + +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests; +using CoreSize = SixLabors.Primitives.Size; +using SDImage = System.Drawing.Image; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg +{ + /// + /// Image-specific Jpeg benchmarks + /// + [Config(typeof(Config.ShortClr))] + public class DecodeJpeg_ImageSpecific + { + public class Config : ManualConfig + { + public Config() + { + // Uncomment if you want to use any of the diagnoser + this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); + } + + public class ShortClr : Benchmarks.Config + { + public ShortClr() + { + this.Add( + //Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3), + Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3) + ); + } + } + } + + private byte[] jpegBytes; + + private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); + + [Params( + TestImages.Jpeg.Baseline.Lake, + TestImages.Jpeg.Issues.BadRstProgressive518, + TestImages.Jpeg.Issues.ExifGetString750Transform, + + TestImages.Jpeg.Baseline.Jpeg420Exif + )] + public string TestImage { get; set; } + + [GlobalSetup] + public void ReadImages() + { + if (this.jpegBytes == null) + { + this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath); + } + } + + [Benchmark(Baseline = true, Description = "Decode Jpeg - System.Drawing")] + public Size JpegSystemDrawing() + { + using (var memoryStream = new MemoryStream(this.jpegBytes)) + { + using (var image = SDImage.FromStream(memoryStream)) + { + return image.Size; + } + } + } + + [Benchmark(Description = "Decode Jpeg - ImageSharp")] + public CoreSize JpegImageSharp() + { + using (var memoryStream = new MemoryStream(this.jpegBytes)) + { + using (var image = Image.Load(memoryStream, new JpegDecoder(){ IgnoreMetadata = true})) + { + return new CoreSize(image.Width, image.Height); + } + } + } + + // RESULTS (2018 October 31): + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-MCUBGX : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-TZIRPF : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // + // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| + // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.10 ms | 4.720 ms | 0.2667 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | + // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 57.77 ms | 4.626 ms | 0.2614 ms | 3.38 | 0.04 | 125.0000 | 566.01 KB | + // | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | + + // RESULTS (2018 November 4): + // Method | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Gen 1 | Gen 2 | Allocated | + // ------------------------------- |-------------------------------------------- |-----------:|-----------:|----------:|-------:|---------:|----------:|---------:|---------:|------------:| + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/Lake.jpg | 6.291 ms | 1.200 ms | 0.0678 ms | 1.00 | 0.00 | 62.5000 | - | - | 205.83 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/Lake.jpg | 18.493 ms | 3.025 ms | 0.1709 ms | 2.94 | 0.03 | - | - | - | 19.97 KB | + // | | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/jpeg420exif.jpg | 16.962 ms | 1.446 ms | 0.0817 ms | 1.00 | 0.00 | 218.7500 | - | - | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/jpeg420exif.jpg | 42.105 ms | 4.496 ms | 0.2540 ms | 2.48 | 0.02 | - | - | - | 21.94 KB | + // | | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 432.344 ms | 89.746 ms | 5.0708 ms | 1.00 | 0.00 | 2375.0000 | - | - | 7403.76 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 421.292 ms | 128.587 ms | 7.2654 ms | 0.97 | 0.02 | 125.0000 | 125.0000 | 125.0000 | 35186.98 KB | + // | | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/issue750-exif-tranform.jpg | 94.723 ms | 4.663 ms | 0.2635 ms | 1.00 | 0.00 | 1750.0000 | - | - | 5492.63 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/issue750-exif-tranform.jpg | 234.071 ms | 37.979 ms | 2.1459 ms | 2.47 | 0.02 | 312.5000 | 312.5000 | 312.5000 | 58834.45 KB | + } +} diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs index 72062fc7da..b6a4711c4d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } } - // RESULTS (2018 October): + // RESULTS (2018 October 31): // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs new file mode 100644 index 0000000000..111c509cf4 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs @@ -0,0 +1,88 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Tests; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg +{ + [Config(typeof(MultiImageBenchmarkBase.Config))] + public class LoadResizeSave_MultiImage : MultiImageBenchmarkBase + { + protected override IEnumerable InputImageSubfoldersOrFiles => TestImages.Jpeg.BenchmarkSuite; + + [Params(InputImageCategory.AllImages)] + public override InputImageCategory InputCategory { get; set; } + + private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); + + private byte[] destBytes; + + public override void Setup() + { + base.Setup(); + + this.configuration.MaxDegreeOfParallelism = 1; + const int MaxOutputSizeInBytes = 2 * 1024 * 1024; // ~2 MB + this.destBytes = new byte[MaxOutputSizeInBytes]; + } + + [Benchmark(Baseline = true)] + public void SystemDrawing() + { + this.ForEachStream( + sourceStream => + { + using (var destStream = new MemoryStream(this.destBytes)) + using (var source = System.Drawing.Image.FromStream(sourceStream)) + using (var destination = new Bitmap(source.Width / 4, source.Height / 4)) + { + using (var g = Graphics.FromImage(destination)) + { + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.DrawImage(source, 0, 0, 400, 400); + } + + destination.Save(destStream, ImageFormat.Jpeg); + } + + return null; + }); + } + + [Benchmark] + public void ImageSharp() + { + this.ForEachStream( + sourceStream => + { + using (var source = Image.Load( + this.configuration, + sourceStream, + new JpegDecoder { IgnoreMetadata = true })) + { + using (var destStream = new MemoryStream(this.destBytes)) + { + source.Mutate(c => c.Resize(source.Width / 4, source.Height / 4)); + source.SaveAsJpeg(destStream); + } + } + + return null; + }); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index 608d3604f9..446c038596 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -3,6 +3,9 @@ // Licensed under the Apache License, Version 2.0. // +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Jobs; + using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.Codecs @@ -22,6 +25,25 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public abstract class MultiImageBenchmarkBase { + public class Config : ManualConfig + { + public Config() + { + // Uncomment if you want to use any of the diagnoser + this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); + } + + public class ShortClr : Benchmarks.Config + { + public ShortClr() + { + this.Add( + Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithTargetCount(2) + ); + } + } + } + protected Dictionary FileNamesToBytes = new Dictionary(); protected Dictionary> FileNamesToImageSharpImages = new Dictionary>(); @@ -49,7 +71,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs /// /// Gets the file names containing these strings are substrings are not processed by the benchmark. /// - protected IEnumerable ExcludeSubstringsInFileNames => new[] { "badeof", "BadEof", "CriticalEOF" }; + protected virtual IEnumerable ExcludeSubstringsInFileNames => new[] { "badeof", "BadEof", "CriticalEOF" }; /// /// Enumerates folders containing files OR files to be processed by the benchmark. @@ -87,7 +109,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs protected abstract IEnumerable InputImageSubfoldersOrFiles { get; } [GlobalSetup] - public void ReadImages() + public virtual void Setup() { if (!Vector.IsHardwareAccelerated) { @@ -107,11 +129,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs continue; } + string[] excludeStrings = this.ExcludeSubstringsInFileNames.Select(s => s.ToLower()).ToArray(); + string[] allFiles = this.SearchPatterns.SelectMany( f => Directory.EnumerateFiles(path, f, SearchOption.AllDirectories) - .Where(fn => !this.ExcludeSubstringsInFileNames.Any(w => fn.ToLower().Contains(w)))).ToArray(); + .Where(fn => !excludeStrings.Any(excludeStr => fn.ToLower().Contains(excludeStr)))).ToArray(); foreach (string fn in allFiles) { diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index 3d439c5ce7..a7f848e3a9 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -22,15 +22,19 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { } - public static readonly TheoryData DecodeJpegData = new TheoryData() - { - //TestImages.Jpeg.Baseline.Cmyk, - //TestImages.Jpeg.Baseline.Ycck, - TestImages.Jpeg.Baseline.Calliphora, - TestImages.Jpeg.Baseline.Jpeg400, - TestImages.Jpeg.Baseline.Jpeg420Exif, - TestImages.Jpeg.Baseline.Jpeg444, - }; + public static readonly TheoryData DecodeJpegData = new TheoryData + { + // Except "Jpeg400", all images are YCbCr + + TestImages.Jpeg.Baseline.Jpeg400, + TestImages.Jpeg.Baseline.Jpeg420Exif, + TestImages.Jpeg.Baseline.Lake, // 444 + + // Using images from the "issues" set, because they are LARGE + TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, // 420 + TestImages.Jpeg.Issues.BadRstProgressive518, // 444 + TestImages.Jpeg.Issues.ExifGetString750Transform, // 420 + }; [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [MemberData(nameof(DecodeJpegData))] @@ -38,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); } - + private void DecodeJpegBenchmarkImpl(string fileName, IImageDecoder decoder) { // do not run this on CI even by accident @@ -47,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks return; } - const int ExecutionCount = 30; + const int ExecutionCount = 10; if (!Vector.IsHardwareAccelerated) { @@ -83,29 +87,26 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks } string[] testFiles = TestImages.Bmp.All - .Concat(new[] { TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Cmyk }) - .ToArray(); + .Concat(new[] { TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Cmyk }).ToArray(); - Image[] testImages = - testFiles.Select( - tf => TestImageProvider.File(tf, pixelTypeOverride: PixelTypes.Rgba32).GetImage()) - .ToArray(); + Image[] testImages = testFiles.Select( + tf => TestImageProvider.File(tf, pixelTypeOverride: PixelTypes.Rgba32).GetImage()).ToArray(); using (var ms = new MemoryStream()) { - this.Measure(executionCount, + this.Measure( + executionCount, () => - { - foreach (Image img in testImages) { - var options = new JpegEncoder { Quality = quality, Subsample = subsample }; - img.Save(ms, options); - ms.Seek(0, SeekOrigin.Begin); - } - }, + foreach (Image img in testImages) + { + var options = new JpegEncoder { Quality = quality, Subsample = subsample }; + img.Save(ms, options); + ms.Seek(0, SeekOrigin.Begin); + } + }, // ReSharper disable once ExplicitCallerInfoArgument - $@"Encode {testFiles.Length} images" - ); + $@"Encode {testFiles.Length} images"); } foreach (Image image in testImages) @@ -113,6 +114,5 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks image.Dispose(); } } - } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 03f8754854..caffe81ab7 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -165,6 +165,19 @@ namespace SixLabors.ImageSharp.Tests } public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); + + public static readonly string[] BenchmarkSuite = + { + // Except "Jpeg400", all images are YCbCr + Baseline.Jpeg400, + Baseline.Jpeg420Exif, + Baseline.Lake, // 444 + + // Using images from the "issues" set, because they are LARGE + Issues.MissingFF00ProgressiveBedroom159, // 420 + Issues.BadRstProgressive518, // 444 + Issues.ExifGetString750Transform, // 420 + }; } public static class Bmp From 5ea62adeddb2de5d8c3782b4b40ab73a6064c924 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 02:54:21 +0100 Subject: [PATCH 144/238] Drop all GetBlockDataReference() usages --- .../Decoder/JpegComponentExtensions.cs | 39 ------------- .../Jpeg/Components/Decoder/ScanDecoder.cs | 58 +++++++++++-------- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 22 ++++--- .../Jpg/Utils/LibJpegTools.ComponentData.cs | 3 +- 4 files changed, 48 insertions(+), 74 deletions(-) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs deleted file mode 100644 index d7fb52a790..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Runtime.CompilerServices; - -using SixLabors.ImageSharp.Memory; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder -{ - /// - /// Extension methods for - /// - internal static class JpegComponentExtensions - { - /// - /// Gets a reference to the at the given row and column index from - /// - /// The - /// The column - /// The row - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public static ref Block8x8 GetBlockReference(this IJpegComponent component, int column, int row) - { - return ref component.SpectralBlocks.GetRowSpan(row)[column]; - } - - /// - /// Gets a reference to the first item in a block - /// at the given row and column index from - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static ref short GetBlockDataReference(this IJpegComponent component, int column, int row) - { - ref Block8x8 blockRef = ref component.GetBlockReference(column, row); - return ref Unsafe.As(ref blockRef); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index 39b9792ac9..ec9805309e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -1,8 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { @@ -179,10 +181,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int h = component.HorizontalSamplingFactor; int v = component.VerticalSamplingFactor; + int mcuRow = mcu / mcusPerLine; + // Scan out an mcu's worth of this component; that's just determined // by the basic H and V specified for the component for (int y = 0; y < v; y++) { + int blockRow = (mcuRow * v) + y; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); for (int x = 0; x < h; x++) { if (this.eof) @@ -190,15 +196,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int mcuRow = mcu / mcusPerLine; int mcuCol = mcu % mcusPerLine; - int blockRow = (mcuRow * v) + y; int blockCol = (mcuCol * h) + x; this.DecodeBlockBaseline( component, - blockRow, - blockCol, + ref blockSpan[blockCol], ref dcHuffmanTable, ref acHuffmanTable, ref fastACRef); @@ -236,6 +239,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int mcu = 0; for (int j = 0; j < h; j++) { + // TODO: Isn't blockRow == j actually? + int blockRow = mcu / w; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); + for (int i = 0; i < w; i++) { if (this.eof) @@ -243,13 +250,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int blockRow = mcu / w; + // TODO: Isn't blockCol == i actually? int blockCol = mcu % w; this.DecodeBlockBaseline( component, - blockRow, - blockCol, + ref blockSpan[blockCol], ref dcHuffmanTable, ref acHuffmanTable, ref fastACRef); @@ -299,6 +305,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // by the basic H and V specified for the component for (int y = 0; y < v; y++) { + int mcuRow = mcu / mcusPerLine; + int blockRow = (mcuRow * v) + y; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); + for (int x = 0; x < h; x++) { if (this.eof) @@ -306,15 +316,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int mcuRow = mcu / mcusPerLine; int mcuCol = mcu % mcusPerLine; - int blockRow = (mcuRow * v) + y; int blockCol = (mcuCol * h) + x; this.DecodeBlockProgressiveDC( component, - blockRow, - blockCol, + ref blockSpan[blockCol], ref dcHuffmanTable); } } @@ -351,6 +358,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int mcu = 0; for (int j = 0; j < h; j++) { + // TODO: isn't blockRow == j actually? + int blockRow = mcu / w; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); + for (int i = 0; i < w; i++) { if (this.eof) @@ -358,23 +369,23 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int blockRow = mcu / w; + // TODO: isn't blockCol == i actually? int blockCol = mcu % w; + ref Block8x8 block = ref blockSpan[blockCol]; + if (this.spectralStart == 0) { this.DecodeBlockProgressiveDC( component, - blockRow, - blockCol, + ref block, ref dcHuffmanTable); } else { this.DecodeBlockProgressiveAC( component, - blockRow, - blockCol, + ref block, ref acHuffmanTable, ref fastACRef); } @@ -391,8 +402,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void DecodeBlockBaseline( JpegComponent component, - int row, - int col, + ref Block8x8 block, ref HuffmanTable dcTable, ref HuffmanTable acTable, ref short fastACRef) @@ -405,7 +415,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder JpegThrowHelper.ThrowBadHuffmanCode(); } - ref short blockDataRef = ref component.GetBlockDataReference(col, row); + ref short blockDataRef = ref Unsafe.As(ref block); int diff = t != 0 ? this.ExtendReceive(t) : 0; int dc = component.DcPredictor + diff; @@ -470,8 +480,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void DecodeBlockProgressiveDC( JpegComponent component, - int row, - int col, + ref Block8x8 block, ref HuffmanTable dcTable) { if (this.spectralEnd != 0) @@ -481,7 +490,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.CheckBits(); - ref short blockDataRef = ref component.GetBlockDataReference(col, row); + ref short blockDataRef = ref Unsafe.As(ref block); if (this.successiveHigh == 0) { @@ -506,8 +515,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void DecodeBlockProgressiveAC( JpegComponent component, - int row, - int col, + ref Block8x8 block, ref HuffmanTable acTable, ref short fastACRef) { @@ -516,7 +524,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder JpegThrowHelper.ThrowImageFormatException("Can't merge DC and AC."); } - ref short blockDataRef = ref component.GetBlockDataReference(col, row); + ref short blockDataRef = ref Unsafe.As(ref block); if (this.successiveHigh == 0) { diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index e161bca05b..9292d5f7de 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -46,15 +46,19 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); + // NOTE: + // The scaled result for very large image "TestImages.Jpeg.Issues.ExifGetString750Transform" + // is almost the same as the result for Jpeg420Exif, + // which proves that the execution time for the most common YCbCr 420 path scales linearly [Params( TestImages.Jpeg.Baseline.Lake, TestImages.Jpeg.Issues.BadRstProgressive518, - TestImages.Jpeg.Issues.ExifGetString750Transform, TestImages.Jpeg.Baseline.Jpeg420Exif )] public string TestImage { get; set; } + [GlobalSetup] public void ReadImages() { @@ -110,16 +114,16 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg // RESULTS (2018 November 4): // Method | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Gen 1 | Gen 2 | Allocated | // ------------------------------- |-------------------------------------------- |-----------:|-----------:|----------:|-------:|---------:|----------:|---------:|---------:|------------:| - // 'Decode Jpeg - System.Drawing' | Jpg/baseline/Lake.jpg | 6.291 ms | 1.200 ms | 0.0678 ms | 1.00 | 0.00 | 62.5000 | - | - | 205.83 KB | - // 'Decode Jpeg - ImageSharp' | Jpg/baseline/Lake.jpg | 18.493 ms | 3.025 ms | 0.1709 ms | 2.94 | 0.03 | - | - | - | 19.97 KB | + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/Lake.jpg | 6.117 ms | 0.3923 ms | 0.0222 ms | 1.00 | 0.00 | 62.5000 | - | - | 205.83 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/Lake.jpg | 18.126 ms | 0.6023 ms | 0.0340 ms | 2.96 | 0.01 | - | - | - | 19.97 KB | // | | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Jpg/baseline/jpeg420exif.jpg | 16.962 ms | 1.446 ms | 0.0817 ms | 1.00 | 0.00 | 218.7500 | - | - | 757.04 KB | - // 'Decode Jpeg - ImageSharp' | Jpg/baseline/jpeg420exif.jpg | 42.105 ms | 4.496 ms | 0.2540 ms | 2.48 | 0.02 | - | - | - | 21.94 KB | + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/jpeg420exif.jpg | 17.063 ms | 2.6096 ms | 0.1474 ms | 1.00 | 0.00 | 218.7500 | - | - | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/jpeg420exif.jpg | 41.366 ms | 1.0115 ms | 0.0572 ms | 2.42 | 0.02 | - | - | - | 21.94 KB | // | | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 432.344 ms | 89.746 ms | 5.0708 ms | 1.00 | 0.00 | 2375.0000 | - | - | 7403.76 KB | - // 'Decode Jpeg - ImageSharp' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 421.292 ms | 128.587 ms | 7.2654 ms | 0.97 | 0.02 | 125.0000 | 125.0000 | 125.0000 | 35186.98 KB | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 428.282 ms | 94.9163 ms | 5.3629 ms | 1.00 | 0.00 | 2375.0000 | - | - | 7403.76 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 386.698 ms | 33.0065 ms | 1.8649 ms | 0.90 | 0.01 | 125.0000 | 125.0000 | 125.0000 | 35186.97 KB | // | | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Jpg/issues/issue750-exif-tranform.jpg | 94.723 ms | 4.663 ms | 0.2635 ms | 1.00 | 0.00 | 1750.0000 | - | - | 5492.63 KB | - // 'Decode Jpeg - ImageSharp' | Jpg/issues/issue750-exif-tranform.jpg | 234.071 ms | 37.979 ms | 2.1459 ms | 2.47 | 0.02 | 312.5000 | 312.5000 | 312.5000 | 58834.45 KB | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/issue750-exif-tranform.jpg | 95.192 ms | 3.1762 ms | 0.1795 ms | 1.00 | 0.00 | 1750.0000 | - | - | 5492.63 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/issue750-exif-tranform.jpg | 230.158 ms | 48.8128 ms | 2.7580 ms | 2.42 | 0.02 | 312.5000 | 312.5000 | 312.5000 | 58834.66 KB | } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs index 7acce84cea..e4fcd10c5f 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs @@ -67,9 +67,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils for (int y = 0; y < result.HeightInBlocks; y++) { + Span blockRow = c.SpectralBlocks.GetRowSpan(y); for (int x = 0; x < result.WidthInBlocks; x++) { - short[] data = c.GetBlockReference(x, y).ToArray(); + short[] data = blockRow[x].ToArray(); result.MakeBlock(data, y, x); } } From 86489b8ac634502b927d802801fa73029d5d7459 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 03:32:43 +0100 Subject: [PATCH 145/238] simplify benchmark suite --- tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index a7f848e3a9..06eb203d5f 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks // Using images from the "issues" set, because they are LARGE TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, // 420 - TestImages.Jpeg.Issues.BadRstProgressive518, // 444 + // TestImages.Jpeg.Issues.BadRstProgressive518, // 444 TestImages.Jpeg.Issues.ExifGetString750Transform, // 420 }; diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index caffe81ab7..35de87228f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.Tests // Using images from the "issues" set, because they are LARGE Issues.MissingFF00ProgressiveBedroom159, // 420 - Issues.BadRstProgressive518, // 444 + // Issues.BadRstProgressive518, // 444 Issues.ExifGetString750Transform, // 420 }; } From 2ff5b9c47676cf9d456bad29fd3c5d501f240c38 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 03:35:04 +0100 Subject: [PATCH 146/238] drop old benchmark results --- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index 9292d5f7de..206a33729f 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -92,26 +92,14 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } } - // RESULTS (2018 October 31): + // RESULTS (2018 November 4): // // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC // .NET Core SDK=2.1.403 // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT - // Job-MCUBGX : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 - // Job-TZIRPF : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT - // // - // Method | Runtime | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ------------------------------- |-------- |----------------------------- |---------:|----------:|----------:|-------:|---------:|---------:|----------:| - // 'Decode Jpeg - System.Drawing' | Clr | Jpg/baseline/jpeg420exif.jpg | 17.10 ms | 4.720 ms | 0.2667 ms | 1.00 | 0.00 | 218.7500 | 757.88 KB | - // 'Decode Jpeg - ImageSharp' | Clr | Jpg/baseline/jpeg420exif.jpg | 57.77 ms | 4.626 ms | 0.2614 ms | 3.38 | 0.04 | 125.0000 | 566.01 KB | - // | | | | | | | | | | - // 'Decode Jpeg - System.Drawing' | Core | Jpg/baseline/jpeg420exif.jpg | 17.45 ms | 2.092 ms | 0.1182 ms | 1.00 | 0.00 | 218.7500 | 757.04 KB | - // 'Decode Jpeg - ImageSharp' | Core | Jpg/baseline/jpeg420exif.jpg | 48.39 ms | 14.562 ms | 0.8228 ms | 2.77 | 0.04 | 125.0000 | 529.96 KB | - - // RESULTS (2018 November 4): // Method | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Gen 1 | Gen 2 | Allocated | // ------------------------------- |-------------------------------------------- |-----------:|-----------:|----------:|-------:|---------:|----------:|---------:|---------:|------------:| // 'Decode Jpeg - System.Drawing' | Jpg/baseline/Lake.jpg | 6.117 ms | 0.3923 ms | 0.0222 ms | 1.00 | 0.00 | 62.5000 | - | - | 205.83 KB | From 5c65cca162c08e9455bc7eb26e4b63a760bbe6a5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 14:24:17 +0100 Subject: [PATCH 147/238] fix Block8x8FTests.Copy1x1Scale, reorganize TestImages.Jpeg.BenchmarkSuite as a static class --- ...pegMultiple.cs => DecodeJpeg_Aggregate.cs} | 21 +++++++++++++------ .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 18 +++++++++------- ...tiImage.cs => LoadResizeSave_Aggregate.cs} | 12 +++++++++-- ...ave.cs => LoadResizeSave_ImageSpecific.cs} | 9 +++++--- .../Jpg/Block8x8FTests.CopyToBufferArea.cs | 2 +- .../ProfilingBenchmarks/JpegBenchmarks.cs | 19 +++++++---------- tests/ImageSharp.Tests/TestImages.cs | 21 +++++++++---------- 7 files changed, 59 insertions(+), 43 deletions(-) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{DecodeJpegMultiple.cs => DecodeJpeg_Aggregate.cs} (56%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{LoadResizeSave_MultiImage.cs => LoadResizeSave_Aggregate.cs} (84%) rename tests/ImageSharp.Benchmarks/Codecs/Jpeg/{LoadResizeSave.cs => LoadResizeSave_ImageSpecific.cs} (94%) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs similarity index 56% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs index 53459e3c45..f8a7556ca5 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests; using SDImage = System.Drawing.Image; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { @@ -17,21 +18,29 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg /// An expensive Jpeg benchmark, running on a wide range of input images, showing aggregate results. /// [Config(typeof(MultiImageBenchmarkBase.Config))] - public class DecodeJpegMultiple : MultiImageBenchmarkBase + public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase { - protected override IEnumerable InputImageSubfoldersOrFiles => TestImages.Jpeg.BenchmarkSuite; + protected override IEnumerable InputImageSubfoldersOrFiles => + new[] + { + TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + }; [Params(InputImageCategory.AllImages)] public override InputImageCategory InputCategory { get; set; } - [Benchmark(Description = "DecodeJpegMultiple - ImageSharp")] - public void DecodeJpegImageSharp() + [Benchmark] + public void ImageSharp() { this.ForEachStream(ms => Image.Load(ms, new JpegDecoder())); } - [Benchmark(Baseline = true, Description = "DecodeJpegMultiple - System.Drawing")] - public void DecodeJpegSystemDrawing() + [Benchmark(Baseline = true)] + public void SystemDrawing() { this.ForEachStream(SDImage.FromStream); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index 206a33729f..fe112042ef 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -45,16 +45,18 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg private byte[] jpegBytes; private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); - - // NOTE: - // The scaled result for very large image "TestImages.Jpeg.Issues.ExifGetString750Transform" - // is almost the same as the result for Jpeg420Exif, - // which proves that the execution time for the most common YCbCr 420 path scales linearly + [Params( - TestImages.Jpeg.Baseline.Lake, - TestImages.Jpeg.Issues.BadRstProgressive518, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, + + // The scaled result for the large image "ExifGetString750Transform_Huge420YCbCr" + // is almost the same as the result for Jpeg420Exif, + // which proves that the execution time for the most common YCbCr 420 path scales linearly. + // + // TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, - TestImages.Jpeg.Baseline.Jpeg420Exif + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr )] public string TestImage { get; set; } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs similarity index 84% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs index 111c509cf4..e39cfa6ba2 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_MultiImage.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs @@ -18,9 +18,17 @@ using SixLabors.ImageSharp.Tests; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { [Config(typeof(MultiImageBenchmarkBase.Config))] - public class LoadResizeSave_MultiImage : MultiImageBenchmarkBase + public class LoadResizeSave_Aggregate : MultiImageBenchmarkBase { - protected override IEnumerable InputImageSubfoldersOrFiles => TestImages.Jpeg.BenchmarkSuite; + protected override IEnumerable InputImageSubfoldersOrFiles => + new[] + { + TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + }; [Params(InputImageCategory.AllImages)] public override InputImageCategory InputCategory { get; set; } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs similarity index 94% rename from tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs index b6a4711c4d..1834f77eaf 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs @@ -11,11 +11,12 @@ using System.Drawing.Imaging; using SixLabors.ImageSharp.Processing; using SDImage = System.Drawing.Image; using SixLabors.ImageSharp.Formats.Jpeg; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { [Config(typeof(Config.ShortClr))] - public class LoadResizeSave + public class LoadResizeSave_ImageSpecific { private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); @@ -26,8 +27,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); [Params( - TestImages.Jpeg.Baseline.Jpeg420Exif - //, TestImages.Jpeg.Baseline.Calliphora + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, + + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr )] public string TestImage { get; set; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index d5eaaa2949..4b1abf9094 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { Block8x8F block = CreateRandomFloatBlock(0, 100); - using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20, AllocationOptions.Clean)) { BufferArea area = buffer.GetArea(5, 10, 8, 8); block.Copy1x1Scale(area); diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index 06eb203d5f..5bc1693bcc 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -23,18 +23,13 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks } public static readonly TheoryData DecodeJpegData = new TheoryData - { - // Except "Jpeg400", all images are YCbCr - - TestImages.Jpeg.Baseline.Jpeg400, - TestImages.Jpeg.Baseline.Jpeg420Exif, - TestImages.Jpeg.Baseline.Lake, // 444 - - // Using images from the "issues" set, because they are LARGE - TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, // 420 - // TestImages.Jpeg.Issues.BadRstProgressive518, // 444 - TestImages.Jpeg.Issues.ExifGetString750Transform, // 420 - }; + { + TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + }; [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [MemberData(nameof(DecodeJpegData))] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 35de87228f..8da458e520 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -166,18 +166,17 @@ namespace SixLabors.ImageSharp.Tests public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); - public static readonly string[] BenchmarkSuite = + public static class BenchmarkSuite { - // Except "Jpeg400", all images are YCbCr - Baseline.Jpeg400, - Baseline.Jpeg420Exif, - Baseline.Lake, // 444 - - // Using images from the "issues" set, because they are LARGE - Issues.MissingFF00ProgressiveBedroom159, // 420 - // Issues.BadRstProgressive518, // 444 - Issues.ExifGetString750Transform, // 420 - }; + public const string Jpeg400_SmallMonochrome = Baseline.Jpeg400; + public const string Jpeg420Exif_MidSizeYCbCr = Baseline.Jpeg420Exif; + public const string Lake_Small444YCbCr = Baseline.Lake; + + // A few large images from the "issues" set are actually very useful for benchmarking: + public const string MissingFF00ProgressiveBedroom159_MidSize420YCbCr = Issues.MissingFF00ProgressiveBedroom159; + public const string BadRstProgressive518_Large444YCbCr = Issues.BadRstProgressive518; + public const string ExifGetString750Transform_Huge420YCbCr = Issues.ExifGetString750Transform; + } } public static class Bmp From fd1ce9842c8d8f4bc1b8a7b2e291454e9684116d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 14:49:03 +0100 Subject: [PATCH 148/238] oops --- tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs index 267c70219e..f9a68d4e7c 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. // Uncomment to enable local profiling benchmarks. DO NOT PUSH TO MAIN! -#define PROFILING +// #define PROFILING namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { From 300ee6a555455624ab9d025be6be9a6b14040262 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 16:11:45 +0100 Subject: [PATCH 149/238] move ResizeProfilingBenchmarks, use the ***ProfilingBenchmarks naming convention everywhere --- tests/ImageSharp.Sandbox46/Program.cs | 4 ++-- .../{JpegBenchmarks.cs => JpegProfilingBenchmarks.cs} | 4 ++-- ...hmarks.cs => LoadResizeSaveProfilingBenchmarks.cs} | 4 ++-- .../ResizeProfilingBenchmarks.cs | 11 ++--------- 4 files changed, 8 insertions(+), 15 deletions(-) rename tests/ImageSharp.Tests/ProfilingBenchmarks/{JpegBenchmarks.cs => JpegProfilingBenchmarks.cs} (96%) rename tests/ImageSharp.Tests/ProfilingBenchmarks/{LoadResizeSaveBenchmarks.cs => LoadResizeSaveProfilingBenchmarks.cs} (89%) rename tests/ImageSharp.Tests/{Processing/Processors/Transforms => ProfilingBenchmarks}/ResizeProfilingBenchmarks.cs (82%) diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index c0bb25a1b9..02d4f80c55 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -63,8 +63,8 @@ namespace SixLabors.ImageSharp.Sandbox46 private static void RunDecodeJpegProfilingTests() { Console.WriteLine("RunDecodeJpegProfilingTests..."); - var benchmarks = new JpegBenchmarks(new ConsoleOutput()); - foreach (object[] data in JpegBenchmarks.DecodeJpegData) + var benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); + foreach (object[] data in JpegProfilingBenchmarks.DecodeJpegData) { string fileName = (string)data[0]; benchmarks.DecodeJpeg(fileName); diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs similarity index 96% rename from tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index 5bc1693bcc..609aa43b74 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs @@ -15,9 +15,9 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { - public class JpegBenchmarks : MeasureFixture + public class JpegProfilingBenchmarks : MeasureFixture { - public JpegBenchmarks(ITestOutputHelper output) + public JpegProfilingBenchmarks(ITestOutputHelper output) : base(output) { } diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs similarity index 89% rename from tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs index 3060722768..95fe4e48f1 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs @@ -10,9 +10,9 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { - public class LoadResizeSaveBenchmarks : MeasureFixture + public class LoadResizeSaveProfilingBenchmarks : MeasureFixture { - public LoadResizeSaveBenchmarks(ITestOutputHelper output) + public LoadResizeSaveProfilingBenchmarks(ITestOutputHelper output) : base(output) { } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs similarity index 82% rename from tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs index e24458d384..8b93559381 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs @@ -7,17 +7,10 @@ using SixLabors.ImageSharp.Processing; using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { public class ResizeProfilingBenchmarks : MeasureFixture { - public const string SkipText = -#if false - null; -#else - "Benchmark, enable manually!"; -#endif - private readonly Configuration configuration = Configuration.CreateDefaultInstance(); public ResizeProfilingBenchmarks(ITestOutputHelper output) @@ -28,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public int ExecutionCount { get; set; } = 50; - [Theory(Skip = SkipText)] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [InlineData(100, 100)] [InlineData(2000, 2000)] public void ResizeBicubic(int width, int height) From f45ed5dee0611426555677328e8e747179396c69 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 16:59:15 +0100 Subject: [PATCH 150/238] simplify ResizeKernel.Convolve(...) --- .../Processing/Processors/Transforms/ResizeKernel.cs | 4 ++-- .../Processors/Transforms/ResizeProcessor.cs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index cc3c204534..be4b7a741d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -73,11 +73,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The source row position. /// The weighted sum [MethodImpl(InliningOptions.ShortMethod)] - public Vector4 Convolve(Span rowSpan, int sourceX) + public Vector4 Convolve(Span rowSpan) { ref float horizontalValues = ref this.GetStartReference(); int left = this.Left; - ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left + sourceX); + ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left); // Destination color components Vector4 result = Vector4.Zero; diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 4d4ed06ce1..d0d225d9bf 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -254,8 +254,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { for (int y = rows.Min; y < rows.Max; y++) { - Span sourceRow = source.GetPixelRowSpan(y); - Span tempRowSpan = tempRowBuffer.Span; + Span sourceRow = source.GetPixelRowSpan(y).Slice(sourceX); + Span tempRowSpan = tempRowBuffer.Span.Slice(sourceX); PixelOperations.Instance.ToVector4(configuration, sourceRow, tempRowSpan); Vector4Utils.Premultiply(tempRowSpan); @@ -271,7 +271,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = - window.Convolve(tempRowSpan, sourceX); + window.Convolve(tempRowSpan); } } }); @@ -295,10 +295,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = 0; x < width; x++) { - Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x); + Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x).Slice(sourceY); // Destination color components - Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn, sourceY); + Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn); } Vector4Utils.UnPremultiply(tempRowSpan); From 32e0497dca2f1921d5903ef82f69c6d564728237 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 19:59:06 +0100 Subject: [PATCH 151/238] minor refactor on ResizeKernel --- .../Processors/Transforms/KernelMap.cs | 3 ++- .../Processors/Transforms/ResizeKernel.cs | 22 ++++--------------- .../Processors/Transforms/KernelMapTests.cs | 14 +++++++----- 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index 277be53fff..f7a3a6f6de 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.Memory; @@ -89,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ResizeKernel ws = result.CreateKernel(i, left, right); result.Kernels[i] = ws; - ref float weightsBaseRef = ref ws.GetStartReference(); + ref float weightsBaseRef = ref MemoryMarshal.GetReference(ws.GetValues()); for (int j = left; j <= right; j++) { diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index be4b7a741d..707f1467b0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -2,13 +2,11 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { @@ -18,12 +16,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal struct ResizeKernel { /// - /// The local left index position + /// The left index for the destination row /// public int Left; /// - /// The length of the weights window + /// The length of the kernel /// public int Length; @@ -48,34 +46,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.Length = length; } - /// - /// Gets a reference to the first item of the window. - /// - /// The reference to the first item of the window - [MethodImpl(InliningOptions.ShortMethod)] - public ref float GetStartReference() - { - Span span = this.buffer.Span; - return ref span[0]; - } - /// /// Gets the span representing the portion of the that this window covers /// /// The [MethodImpl(InliningOptions.ShortMethod)] - public Span GetSpan() => this.buffer.Span; + public Span GetValues() => this.buffer.Span; /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. /// /// The input span of vectors - /// The source row position. /// The weighted sum [MethodImpl(InliningOptions.ShortMethod)] public Vector4 Convolve(Span rowSpan) { - ref float horizontalValues = ref this.GetStartReference(); + ref float horizontalValues = ref MemoryMarshal.GetReference(this.GetValues()); int left = this.Left; ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 1b4b3cf6a3..a7d93ad1d8 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -21,10 +21,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms this.Output = output; } - [Theory(Skip = "TODO: Add asserionts")] + [Theory] [InlineData(500, 200, nameof(KnownResamplers.Bicubic))] [InlineData(50, 40, nameof(KnownResamplers.Bicubic))] [InlineData(40, 30, nameof(KnownResamplers.Bicubic))] + [InlineData(15, 10, nameof(KnownResamplers.Bicubic))] [InlineData(500, 200, nameof(KnownResamplers.Lanczos8))] [InlineData(100, 80, nameof(KnownResamplers.Lanczos8))] [InlineData(100, 10, nameof(KnownResamplers.Lanczos8))] @@ -37,14 +38,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var bld = new StringBuilder(); - foreach (ResizeKernel window in kernelMap.Kernels) + foreach (ResizeKernel kernel in kernelMap.Kernels) { - Span span = window.GetSpan(); - for (int i = 0; i < window.Length; i++) + bld.Append($"({kernel.Left:D3}) || "); + Span span = kernel.GetValues(); + for (int i = 0; i < kernel.Length; i++) { float value = span[i]; - bld.Append($"{value,7:F4}"); - bld.Append("| "); + bld.Append($"{value,7:F5}"); + bld.Append(" | "); } bld.AppendLine(); From 99a641625c4b3ef46c4a6b67ad694c6a2c7c5206 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 20:44:22 +0100 Subject: [PATCH 152/238] drop unused parameter --- src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs | 2 -- tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index ec9805309e..5d232b5713 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -384,7 +384,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder else { this.DecodeBlockProgressiveAC( - component, ref block, ref acHuffmanTable, ref fastACRef); @@ -514,7 +513,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } private void DecodeBlockProgressiveAC( - JpegComponent component, ref Block8x8 block, ref HuffmanTable acTable, ref short fastACRef) diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs index 5bc1693bcc..e06d2da916 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegBenchmarks.cs @@ -28,6 +28,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, }; @@ -46,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks return; } - const int ExecutionCount = 10; + const int ExecutionCount = 20; if (!Vector.IsHardwareAccelerated) { From f425190dc7f7bb0c686d251cb31f04d3b9785b84 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 21:59:18 +0100 Subject: [PATCH 153/238] Cover KernelMap with tests --- .../Processors/Transforms/KernelMap.cs | 18 ++-- .../Processors/Transforms/ResizeProcessor.cs | 8 +- .../KernelMapTests.ReferenceKernelMap.cs | 99 +++++++++++++++++++ .../Processors/Transforms/KernelMapTests.cs | 42 +++++--- 4 files changed, 145 insertions(+), 22 deletions(-) create mode 100644 tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index f7a3a6f6de..b0fd0e2cde 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { private readonly Buffer2D data; + private readonly ResizeKernel[] kernels; + /// /// Initializes a new instance of the class. /// @@ -25,15 +27,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The radius of the kernel public KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) { + this.DestinationSize = destinationSize; int width = (int)Math.Ceiling(kernelRadius * 2); this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); - this.Kernels = new ResizeKernel[destinationSize]; + this.kernels = new ResizeKernel[destinationSize]; } - /// - /// Gets the calculated values. - /// - public ResizeKernel[] Kernels { get; } + public int DestinationSize { get; } /// /// Disposes instance releasing it's backing buffer. @@ -43,6 +43,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.data.Dispose(); } + /// + /// Returns a for an index value between 0 and destinationSize - 1. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public ref ResizeKernel GetKernel(int destIdx) => ref this.kernels[destIdx]; + /// /// Computes the weights to apply at each pixel when resizing. /// @@ -88,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float sum = 0; ResizeKernel ws = result.CreateKernel(i, left, right); - result.Kernels[i] = ws; + result.kernels[i] = ws; ref float weightsBaseRef = ref MemoryMarshal.GetReference(ws.GetValues()); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index d0d225d9bf..7c9d39fc55 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -269,9 +269,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = minX; x < maxX; x++) { - ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; + ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - startX); Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = - window.Convolve(tempRowSpan); + kernel.Convolve(tempRowSpan); } } }); @@ -289,7 +289,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int y = rows.Min; y < rows.Max; y++) { // Ensure offsets are normalized for cropping and padding. - ResizeKernel window = this.verticalKernelMap.Kernels[y - startY]; + ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY); ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempRowSpan); @@ -298,7 +298,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x).Slice(sourceY); // Destination color components - Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn); + Unsafe.Add(ref tempRowBase, x) = kernel.Convolve(firstPassColumn); } Vector4Utils.UnPremultiply(tempRowSpan); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs new file mode 100644 index 0000000000..932ea54948 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; + +using SixLabors.ImageSharp.Processing.Processors.Transforms; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms +{ + public partial class KernelMapTests + { + /// + /// Simplified reference implementation for functionality. + /// + public class ReferenceKernelMap + { + private readonly ReferenceKernel[] kernels; + + public ReferenceKernelMap(ReferenceKernel[] kernels) + { + this.kernels = kernels; + } + + public int DestinationSize => this.kernels.Length; + + public ReferenceKernel GetKernel(int destinationIndex) => this.kernels[destinationIndex]; + + public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize) + { + float ratio = (float)sourceSize / destinationSize; + float scale = ratio; + + if (scale < 1F) + { + scale = 1F; + } + + float radius = MathF.Ceiling(scale * sampler.Radius); + + var result = new List(); + + for (int i = 0; i < destinationSize; i++) + { + float center = ((i + .5F) * ratio) - .5F; + + // Keep inside bounds. + int left = (int)MathF.Ceiling(center - radius); + if (left < 0) + { + left = 0; + } + + int right = (int)MathF.Floor(center + radius); + if (right > sourceSize - 1) + { + right = sourceSize - 1; + } + + float sum = 0; + + float[] values = new float[right - left + 1]; + + for (int j = left; j <= right; j++) + { + float weight = sampler.GetValue((j - center) / scale); + sum += weight; + + values[j - left] = weight; + } + + result.Add(new ReferenceKernel(left, values)); + + if (sum > 0) + { + for (int w = 0; w < values.Length; w++) + { + values[w] /= sum; + } + } + } + + return new ReferenceKernelMap(result.ToArray()); + } + } + + public struct ReferenceKernel + { + public ReferenceKernel(int left, float[] values) + { + this.Left = left; + this.Values = values; + } + + public int Left { get; } + + public float[] Values { get; } + + public int Length => this.Values.Length; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index a7d93ad1d8..9f4d53b964 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -12,7 +12,7 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { - public class KernelMapTests + public partial class KernelMapTests { private ITestOutputHelper Output { get; } @@ -30,34 +30,52 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [InlineData(100, 80, nameof(KnownResamplers.Lanczos8))] [InlineData(100, 10, nameof(KnownResamplers.Lanczos8))] [InlineData(10, 100, nameof(KnownResamplers.Lanczos8))] - public void PrintKernelMap(int srcSize, int destSize, string resamplerName) + public void KernelMapContentIsCorrect(int srcSize, int destSize, string resamplerName) { var resampler = (IResampler)typeof(KnownResamplers).GetProperty(resamplerName).GetValue(null); var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); + var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); + +#if DEBUG + string text = PrintKernelMap(kernelMap); + this.Output.WriteLine(text); +#endif + + for (int i = 0; i < kernelMap.DestinationSize; i++) + { + ResizeKernel kernel = kernelMap.GetKernel(i); + + ReferenceKernel referenceKernel = referenceMap.GetKernel(i); + + Assert.Equal(referenceKernel.Length, kernel.Length); + Assert.Equal(referenceKernel.Left, kernel.Left); + Assert.True(kernel.GetValues().SequenceEqual(referenceKernel.Values)); + } + } + + private static string PrintKernelMap(KernelMap kernelMap) + { var bld = new StringBuilder(); - foreach (ResizeKernel kernel in kernelMap.Kernels) + for (int i = 0; i < kernelMap.DestinationSize; i++) { + ResizeKernel kernel = kernelMap.GetKernel(i); bld.Append($"({kernel.Left:D3}) || "); Span span = kernel.GetValues(); - for (int i = 0; i < kernel.Length; i++) + + for (int j = 0; j < kernel.Length; j++) { - float value = span[i]; - bld.Append($"{value,7:F5}"); + float value = span[j]; + bld.Append($"{value,8:F5}"); bld.Append(" | "); } bld.AppendLine(); } - string outDir = TestEnvironment.CreateOutputDirectory("." + nameof(this.PrintKernelMap)); - string fileName = $@"{outDir}\{resamplerName}_{srcSize}_{destSize}.MD"; - - File.WriteAllText(fileName, bld.ToString()); - - this.Output.WriteLine(bld.ToString()); + return bld.ToString(); } } } \ No newline at end of file From 41972e90c8e1f69b14d920adc368a8fd8c6f3db2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 4 Nov 2018 22:17:46 +0100 Subject: [PATCH 154/238] refactor ResizeKernel creation --- .../Processors/Transforms/KernelMap.cs | 13 ++++--- .../Processors/Transforms/ResizeKernel.cs | 34 ++++++++----------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index b0fd0e2cde..278fd93d82 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The to use for allocations. /// The size of the destination window /// The radius of the kernel - public KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) + private KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) { this.DestinationSize = destinationSize; int width = (int)Math.Ceiling(kernelRadius * 2); @@ -125,13 +125,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Slices a weights value at the given positions. /// - /// The index in destination buffer - /// The local left index value - /// The local right index value - /// The weights - private ResizeKernel CreateKernel(int destIdx, int leftIdx, int rightIdx) + private ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) { - return new ResizeKernel(destIdx, leftIdx, this.data, rightIdx - leftIdx + 1); + int flatStartIndex = destIdx * this.data.Width; + int length = rightIdx - left + 1; + Memory bufferSlice = this.data.Memory.Slice(flatStartIndex, length); + return new ResizeKernel(left, bufferSlice); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index 707f1467b0..1ce9c9c91e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -16,42 +16,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal struct ResizeKernel { /// - /// The left index for the destination row + /// Initializes a new instance of the struct. /// - public int Left; + [MethodImpl(InliningOptions.ShortMethod)] + internal ResizeKernel(int left, Memory bufferSlice) + { + this.Left = left; + this.BufferSlice = bufferSlice; + } /// - /// The length of the kernel + /// Gets the left index for the destination row /// - public int Length; + public int Left { get; } /// - /// The buffer containing the weights values. + /// Gets the slice of the buffer containing the weights values. /// - private readonly Memory buffer; + public Memory BufferSlice { get; } /// - /// Initializes a new instance of the struct. + /// Gets the the length of the kernel /// - /// The destination index in the buffer - /// The local left index - /// The span - /// The length of the window - [MethodImpl(InliningOptions.ShortMethod)] - internal ResizeKernel(int index, int left, Buffer2D buffer, int length) - { - int flatStartIndex = index * buffer.Width; - this.Left = left; - this.buffer = buffer.MemorySource.Memory.Slice(flatStartIndex, length); - this.Length = length; - } + public int Length => this.BufferSlice.Length; /// /// Gets the span representing the portion of the that this window covers /// /// The [MethodImpl(InliningOptions.ShortMethod)] - public Span GetValues() => this.buffer.Span; + public Span GetValues() => this.BufferSlice.Span; /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. From 9a122870b00ddb6d381580d155c50b06ee58d88a Mon Sep 17 00:00:00 2001 From: Anton Firsov Date: Mon, 5 Nov 2018 01:33:06 +0100 Subject: [PATCH 155/238] Fix EnumHelper.IsDefined --- src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index c6a5b7d232..100649c0fd 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -567,8 +567,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif [MethodImpl(InliningOptions.ShortMethod)] public static bool IsDefined(int value) { - return Array.BinarySearch(Values, 0, Values.Length, value) > 0; + return Array.BinarySearch(Values, value) >= 0; } } } -} \ No newline at end of file +} From e059620f19f9391e40806d6961bc00813a56494d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 5 Nov 2018 01:34:03 +0100 Subject: [PATCH 156/238] KernelMap refactor WIP --- .../ImageSharp.Drawing.csproj | 3 +- src/ImageSharp/ImageSharp.csproj | 3 +- .../Processors/Transforms/KernelMap.cs | 34 ++++++++++----- .../ImageSharp.Benchmarks.csproj | 3 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +- .../Processors/Transforms/KernelMapTests.cs | 42 ++++++++++++++----- 6 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 1cb3f444f0..6341e1771c 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -5,7 +5,8 @@ $(packageversion) 0.0.1 SixLabors and contributors - netstandard1.3;netstandard2.0 + + netcoreapp2.1 7.3 true true diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 29d29d50d8..e2f55e3c6a 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,7 +5,8 @@ $(packageversion) 0.0.1 Six Labors and contributors - netstandard1.3;netstandard2.0;netcoreapp2.1;net472 + + netcoreapp2.1 true true SixLabors.ImageSharp diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index 278fd93d82..3f984fef0d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -19,16 +19,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ResizeKernel[] kernels; - /// - /// Initializes a new instance of the class. - /// - /// The to use for allocations. - /// The size of the destination window - /// The radius of the kernel - private KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) + private int period; + + private int radius; + + private int periodicRegionMin; + + private int periodicRegionMax; + + private KernelMap(MemoryAllocator memoryAllocator, int destinationSize, int radius, int period) { this.DestinationSize = destinationSize; - int width = (int)Math.Ceiling(kernelRadius * 2); + this.period = period; + this.radius = radius; + this.periodicRegionMin = period + radius; + this.periodicRegionMax = destinationSize - radius; + + int width = radius * 2; this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); this.kernels = new ResizeKernel[destinationSize]; } @@ -71,8 +78,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms scale = 1F; } - float radius = MathF.Ceiling(scale * sampler.Radius); - var result = new KernelMap(memoryAllocator, destinationSize, radius); + int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; + + int radius = (int)MathF.Ceiling(scale * sampler.Radius); + var result = new KernelMap(memoryAllocator, destinationSize, radius, period); for (int i = 0; i < destinationSize; i++) { @@ -122,6 +131,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return result; } + private int ReduceIndex(int destIndex) + { + return destIndex; + } + /// /// Slices a weights value at the given positions. /// diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index a705c9bacb..04a4541b21 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,6 +1,7 @@  - netcoreapp2.1;net461 + + netcoreapp2.1 Exe True SixLabors.ImageSharp.Benchmarks diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 86c1a7a259..75ac7450c8 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,6 +1,7 @@  - net462;net472;netcoreapp2.1 + + netcoreapp2.1 True latest full diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 9f4d53b964..7abc1c3122 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -20,17 +20,39 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { this.Output = output; } - + + /// + /// resamplerName, srcSize, destSize + /// + public static readonly TheoryData KernelMapData = new TheoryData + { + { nameof(KnownResamplers.Bicubic), 15, 10 }, + { nameof(KnownResamplers.Bicubic), 10, 15 }, + { nameof(KnownResamplers.Bicubic), 20, 20 }, + { nameof(KnownResamplers.Bicubic), 50, 40 }, + { nameof(KnownResamplers.Bicubic), 40, 50 }, + { nameof(KnownResamplers.Bicubic), 500, 200 }, + { nameof(KnownResamplers.Bicubic), 200, 500 }, + + { nameof(KnownResamplers.Lanczos3), 16, 12 }, + { nameof(KnownResamplers.Lanczos3), 12, 16 }, + { nameof(KnownResamplers.Lanczos3), 12, 9 }, + { nameof(KnownResamplers.Lanczos3), 9, 12 }, + { nameof(KnownResamplers.Lanczos3), 6, 8 }, + { nameof(KnownResamplers.Lanczos3), 8, 6 }, + + // TODO: What's wrong here: + // { nameof(KnownResamplers.Lanczos3), 20, 12 }, + + {nameof(KnownResamplers.Lanczos8), 500, 200 }, + {nameof(KnownResamplers.Lanczos8), 100, 10 }, + {nameof(KnownResamplers.Lanczos8), 100, 80 }, + {nameof(KnownResamplers.Lanczos8), 10, 100 }, + }; + [Theory] - [InlineData(500, 200, nameof(KnownResamplers.Bicubic))] - [InlineData(50, 40, nameof(KnownResamplers.Bicubic))] - [InlineData(40, 30, nameof(KnownResamplers.Bicubic))] - [InlineData(15, 10, nameof(KnownResamplers.Bicubic))] - [InlineData(500, 200, nameof(KnownResamplers.Lanczos8))] - [InlineData(100, 80, nameof(KnownResamplers.Lanczos8))] - [InlineData(100, 10, nameof(KnownResamplers.Lanczos8))] - [InlineData(10, 100, nameof(KnownResamplers.Lanczos8))] - public void KernelMapContentIsCorrect(int srcSize, int destSize, string resamplerName) + [MemberData(nameof(KernelMapData))] + public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { var resampler = (IResampler)typeof(KnownResamplers).GetProperty(resamplerName).GetValue(null); From e79f26bc7ec9cfca5bedb2309d7b7486c9da79ea Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 5 Nov 2018 10:55:22 +0000 Subject: [PATCH 157/238] Add base becnhmark --- .../InterpolatedTransformProcessorBase.cs | 5 +-- .../ImageSharp.Benchmarks/Samplers/Rotate.cs | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Samplers/Rotate.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs b/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs index c1abb4a5e1..4737a4102c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int i = 0; i < length; i++) { ref float wRef = ref Unsafe.Add(ref weightsRef, i); - wRef = wRef / sum; + wRef /= sum; } } } @@ -90,8 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { for (int x = 0, i = sourceMin; i <= sourceMax; i++, x++) { - float weight = sampler.GetValue(i - point); - Unsafe.Add(ref weightsRef, x) = weight; + Unsafe.Add(ref weightsRef, x) = sampler.GetValue(i - point); } } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs new file mode 100644 index 0000000000..c1456f9d77 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs @@ -0,0 +1,39 @@ +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Benchmarks.Samplers +{ + [Config(typeof(Config.ShortClr))] + public class Rotate + { + [Benchmark] + public Size DoRotate() + { + using (var image = new Image(Configuration.Default, 400, 400, Rgba32.BlanchedAlmond)) + { + image.Mutate(x => x.Rotate(37.5F)); + + return image.Size(); + } + } + } +} + +// Nov 4 2018 +//BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17763 +//Intel Core i7-6600U CPU 2.60GHz(Skylake), 1 CPU, 4 logical and 2 physical cores +//.NET Core SDK = 2.1.403 + +// [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT +// Job-KKDIMW : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 +// Job-IUZRFA : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + +//LaunchCount=1 TargetCount=3 WarmupCount=3 + +// #### BEFORE ####: +// Method | Runtime | Mean | Error | StdDev | Allocated | +//--------- |-------- |---------:|----------:|----------:|----------:| +// DoRotate | Clr | 85.19 ms | 13.379 ms | 0.7560 ms | 6 KB | +// DoRotate | Core | 53.51 ms | 9.512 ms | 0.5375 ms | 4.29 KB | \ No newline at end of file From 0fe5525febe603d5509deed1894ad5829ba8e73e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 5 Nov 2018 10:57:55 +0000 Subject: [PATCH 158/238] Remove unused declaration. --- .../Processors/Quantization/PaletteQuantizer{TPixel}.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index e2f302f1ee..ac143a767b 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -61,8 +61,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } TPixel[] paletteRef = this.palette; - TPixel1[] castPalette = Unsafe.As(ref paletteRef); - return new PaletteFrameQuantizer(this, Unsafe.As(ref paletteRef)); } From 8de843200fb96e78aba7f68fd34eda094233af08 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 5 Nov 2018 13:49:14 +0000 Subject: [PATCH 159/238] Mask the PaletteQuantizer.CreateFrameQuantizer() methods. --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 2 +- .../Quantization/PaletteQuantizer{TPixel}.cs | 36 ++++++--- .../Quantization/OctreeQuantizerTests.cs | 58 ++++++++++++++ .../Quantization/PaletteQuantizerTests.cs | 79 +++++++++++++++++++ .../Quantization/WuQuantizerTests.cs | 58 ++++++++++++++ 5 files changed, 223 insertions(+), 10 deletions(-) create mode 100644 tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs create mode 100644 tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs create mode 100644 tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index de68cd46ee..17ee616072 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(frame)) + using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index ac143a767b..a350adfc0c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public class PaletteQuantizer : IQuantizer where TPixel : struct, IPixel { - private readonly TPixel[] palette; - /// /// Initializes a new instance of the class. /// @@ -44,36 +42,56 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public PaletteQuantizer(TPixel[] palette, IErrorDiffuser diffuser) { Guard.MustBeBetweenOrEqualTo(palette.Length, QuantizerConstants.MinColors, QuantizerConstants.MaxColors, nameof(palette)); - this.palette = palette; + this.Palette = palette; this.Diffuser = diffuser; } /// public IErrorDiffuser Diffuser { get; } + /// + /// Gets the palette. + /// + public TPixel[] Palette { get; } + + /// + /// Creates the generic frame quantizer. + /// + /// The to configure internal operations. + /// The . + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + => ((IQuantizer)this).CreateFrameQuantizer(configuration); + + /// + /// Creates the generic frame quantizer. + /// + /// The to configure internal operations. + /// The maximum number of colors to hold in the color palette. + /// The . + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) + => ((IQuantizer)this).CreateFrameQuantizer(configuration, maxColors); + /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) - where TPixel1 : struct, IPixel + IFrameQuantizer IQuantizer.CreateFrameQuantizer(Configuration configuration) { if (!typeof(TPixel).Equals(typeof(TPixel1))) { throw new InvalidOperationException("Generic method type must be the same as class type."); } - TPixel[] paletteRef = this.palette; + TPixel[] paletteRef = this.Palette; return new PaletteFrameQuantizer(this, Unsafe.As(ref paletteRef)); } /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) - where TPixel1 : struct, IPixel + IFrameQuantizer IQuantizer.CreateFrameQuantizer(Configuration configuration, int maxColors) { if (!typeof(TPixel).Equals(typeof(TPixel1))) { throw new InvalidOperationException("Generic method type must be the same as class type."); } - TPixel[] paletteRef = this.palette; + TPixel[] paletteRef = this.Palette; TPixel1[] castPalette = Unsafe.As(ref paletteRef); maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs new file mode 100644 index 0000000000..b3900325db --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs @@ -0,0 +1,58 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization +{ + public class OctreeQuantizerTests + { + [Fact] + public void OctreeQuantizerConstructor() + { + var quantizer = new OctreeQuantizer(128); + + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + + quantizer = new OctreeQuantizer(false); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Null(quantizer.Diffuser); + + quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + + quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson, 128); + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + } + + [Fact] + public void OctreeQuantizerCanCreateFrameQuantizer() + { + var quantizer = new OctreeQuantizer(); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); + + quantizer = new OctreeQuantizer(false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.False(frameQuantizer.Dither); + Assert.Null(frameQuantizer.Diffuser); + + quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs new file mode 100644 index 0000000000..a4e6edd53e --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization +{ + public class PaletteQuantizerTests + { + private static readonly Rgba32[] Rgb = new Rgba32[] { Rgba32.Red, Rgba32.Green, Rgba32.Blue }; + + [Fact] + public void PaletteQuantizerConstructor() + { + var quantizer = new PaletteQuantizer(Rgb); + + Assert.Equal(Rgb, quantizer.Palette); + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, false); + Assert.Equal(Rgb, quantizer.Palette); + Assert.Null(quantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); + Assert.Equal(Rgb, quantizer.Palette); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + } + + [Fact] + public void PaletteQuantizerCanCreateFrameQuantizer() + { + var quantizer = new PaletteQuantizer(Rgb); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.False(frameQuantizer.Dither); + Assert.Null(frameQuantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); + } + + [Fact] + public void PaletteQuantizerThrowsOnInvalidGenericMethodCall() + { + var quantizer = new PaletteQuantizer(Rgb); + + Assert.Throws(() => ((IQuantizer)quantizer).CreateFrameQuantizer(Configuration.Default)); + } + + [Fact] + public void KnownQuantizersWebSafeTests() + { + IQuantizer quantizer = KnownQuantizers.WebSafe; + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + } + + [Fact] + public void KnownQuantizersWernerTests() + { + IQuantizer quantizer = KnownQuantizers.Werner; + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs new file mode 100644 index 0000000000..625043c7f1 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs @@ -0,0 +1,58 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization +{ + public class WuQuantizerTests + { + [Fact] + public void WuQuantizerConstructor() + { + var quantizer = new WuQuantizer(128); + + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + + quantizer = new WuQuantizer(false); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Null(quantizer.Diffuser); + + quantizer = new WuQuantizer(KnownDiffusers.Atkinson); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + + quantizer = new WuQuantizer(KnownDiffusers.Atkinson, 128); + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + } + + [Fact] + public void WuQuantizerCanCreateFrameQuantizer() + { + var quantizer = new WuQuantizer(); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); + + quantizer = new WuQuantizer(false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.False(frameQuantizer.Dither); + Assert.Null(frameQuantizer.Diffuser); + + quantizer = new WuQuantizer(KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); + } + } +} From 7e519e75019207d42d0aebe1add4d6675be666e1 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 5 Nov 2018 13:27:08 -0600 Subject: [PATCH 160/238] ImageSharp-762_Aot-compiling: moved AoT methods to AotCompiler static class --- src/ImageSharp/Advanced/AotCompiler.cs | 103 ++++++++++++++++++ src/ImageSharp/Formats/Gif/ImageExtensions.cs | 42 ------- 2 files changed, 103 insertions(+), 42 deletions(-) create mode 100644 src/ImageSharp/Advanced/AotCompiler.cs diff --git a/src/ImageSharp/Advanced/AotCompiler.cs b/src/ImageSharp/Advanced/AotCompiler.cs new file mode 100644 index 0000000000..1c7f12ef7b --- /dev/null +++ b/src/ImageSharp/Advanced/AotCompiler.cs @@ -0,0 +1,103 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; +using SixLabors.ImageSharp.Processing.Processors.Quantization; + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Unlike traditional Mono/.NET, code on the iPhone is statically compiled ahead of time instead of being + /// compiled on demand by a JIT compiler. This means there are a few limitations with respect to generics, + /// these are caused because not every possible generic instantiation can be determined up front at compile time. + /// The Aot Compiler is designed to overcome the limitations of this compiler. + /// + public static class AotCompiler + { + /// + /// Seeds the compiler using the given pixel format. + /// + /// The pixel format. + public static void Seed() + where TPixel : struct, IPixel + { + // This is we actually call all the individual methods you need to seed. + AotCompileOctreeQuantizer(); + AotCompileWuQuantizer(); + AotCompileDithering(); + + // TODO: Do the discovery work to figure out what works and what doesn't. + } + + /// + /// Seeds the compiler using the given pixel formats. + /// + /// The first pixel format. + /// The second pixel format. + public static void Seed() + where TPixel : struct, IPixel + where TPixel2 : struct, IPixel + { + Seed(); + Seed(); + } + + /// + /// Seeds the compiler using the given pixel formats. + /// + /// The first pixel format. + /// The second pixel format. + /// The third pixel format. + public static void Seed() + where TPixel : struct, IPixel + where TPixel2 : struct, IPixel + where TPixel3 : struct, IPixel + { + Seed(); + Seed(); + } + + /// + /// This method doesn't actually do anything but serves an important purpose... + /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: + /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." + /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT + /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on + /// iOS so it bombs out. + /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the + /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! + /// + /// The pixel format. + private static void AotCompileOctreeQuantizer() + where TPixel : struct, IPixel + { + var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. + /// + /// The pixel format. + private static void AotCompileWuQuantizer() + where TPixel : struct, IPixel + { + var test = new WuFrameQuantizer(new WuQuantizer(false)); + test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. + /// + /// The pixel format. + private static void AotCompileDithering() + where TPixel : struct, IPixel + { + var test = new FloydSteinbergDiffuser(); + TPixel pixel = default; + test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index f1c2ae5fb5..3939299e90 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -38,47 +38,5 @@ namespace SixLabors.ImageSharp public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); - - /// - /// This method doesn't actually do anything but serves an important purpose... - /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: - /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." - /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT - /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on - /// iOS so it bombs out. - /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the - /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! - /// - /// The pixel format. - public static void AotCompileOctreeQuantizer() - where TPixel : struct, IPixel - { - var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); - test.AotGetPalette(); - } - - /// - /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. - /// - /// The pixel format. - public static void AotCompileWuQuantizer() - where TPixel : struct, IPixel - { - var test = new WuFrameQuantizer(new WuQuantizer(false)); - test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); - test.AotGetPalette(); - } - - /// - /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. - /// - /// The pixel format. - public static void AotCompileDithering() - where TPixel : struct, IPixel - { - var test = new FloydSteinbergDiffuser(); - TPixel pixel = default; - test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); - } } } From 788319b26d99f2ef57fc7b7f25a8466f887390a4 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 5 Nov 2018 13:28:17 -0600 Subject: [PATCH 161/238] ImageSharp-762_Aot-compiling: namespace cleanup --- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 3939299e90..8ddd4247e1 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -5,9 +5,6 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Primitives; -using SixLabors.ImageSharp.Processing.Processors.Dithering; -using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp { From 9e006c734eca190e2d1b5701986c5699aa43bf39 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 11:12:25 +0100 Subject: [PATCH 162/238] fix typos in comments --- .../Processors/Drawing/FillRegionProcessor.cs | 6 +-- .../Processors/Text/DrawTextProcessor.cs | 4 +- .../Processing/SolidBrush{TPixel}.cs | 2 +- .../Advanced/AdvancedImageExtensions.cs | 6 +-- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 2 +- src/ImageSharp/Common/Helpers/SimdUtils.cs | 4 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 2 +- .../Formats/Bmp/IBmpDecoderOptions.cs | 2 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 4 +- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 4 +- src/ImageSharp/Formats/IImageFormat.cs | 4 +- .../Formats/Jpeg/Components/Block8x8.cs | 6 +-- .../Formats/Jpeg/Components/Block8x8F.cs | 4 +- .../JpegColorConverter.FromYCbCrSimd.cs | 4 +- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 2 +- .../ColorConverters/JpegColorConverter.cs | 2 +- .../Jpeg/Components/Decoder/HuffmanTable.cs | 2 +- .../Jpeg/Components/Decoder/IRawJpegData.cs | 2 +- .../Jpeg/Components/Decoder/JFifMarker.cs | 2 +- .../Decoder/JpegBlockPostProcessor.cs | 2 +- .../Decoder/JpegComponentPostProcessor.cs | 2 +- .../Jpeg/Components/Decoder/ScanDecoder.cs | 4 +- .../Components/Encoder/RgbToYCbCrTables.cs | 2 +- .../Jpeg/Components/GenericBlock8x8.cs | 2 +- .../Formats/Jpeg/JpegDecoderCore.cs | 4 +- .../Formats/Png/Chunks/PhysicalChunkData.cs | 2 +- .../Formats/Png/IPngDecoderOptions.cs | 2 +- src/ImageSharp/IImageInfo.cs | 2 +- src/ImageSharp/Image.WrapMemory.cs | 24 +++++------ src/ImageSharp/ImageExtensions.cs | 4 +- src/ImageSharp/Image{TPixel}.cs | 2 +- .../Profiles/ICC/Enums/IccProfileClass.cs | 10 ++--- .../Profiles/ICC/Enums/IccProfileFlag.cs | 4 +- .../Profiles/ICC/Enums/IccProfileTag.cs | 42 +++++++++---------- .../Profiles/ICC/Enums/IccRenderingIntent.cs | 10 ++--- .../Profiles/ICC/Enums/IccTypeSignature.cs | 28 ++++++------- .../PixelFormats/ColorBuilder{TPixel}.cs | 2 +- .../PixelFormats/PixelOperations{TPixel}.cs | 2 +- .../PixelFormats/Utils/PixelConverter.cs | 2 +- .../Utils/Vector4Converters.RgbaCompatible.cs | 2 +- 42 files changed, 111 insertions(+), 111 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 514249a2d4..1dc63efa27 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -82,11 +82,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing // we need to offset the pixel grid to account for when we outline a path. // basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5] // and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the# - // region to alline with the pixel grid. + // region to align with the pixel grid. float offset = 0.5f; if (this.Options.Antialias) { - offset = 0f; // we are antialising skip offsetting as real antalising should take care of offset. + offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset. subpixelCount = this.Options.AntialiasSubpixelDepth; if (subpixelCount < 4) { @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing int pointsFound = region.Scan(subPixel + offset, buffer, configuration); if (pointsFound == 0) { - // nothing on this line skip + // nothing on this line, skip continue; } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index f9a1d87393..487c880644 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text /// The font we want to render with /// The brush to source pixel colors from. /// The pen to outline text with. - /// The location on the image to start drawign the text from. + /// The location on the image to start drawing the text from. public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location) { Guard.NotNull(text, nameof(text)); @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text { base.BeforeImageApply(source, sourceRectangle); - // do everythign at the image level as we are deligating the processing down to other processors + // do everything at the image level as we are delegating the processing down to other processors var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location) { ApplyKerning = this.Options.ApplyKerning, diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs index 6a80287706..20a6833c40 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing { Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x); - // constrain the spans to eachother + // constrain the spans to each other if (destinationRow.Length > scanline.Length) { destinationRow = destinationRow.Slice(0, scanline.Length); diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 328d575969..63ccea4e66 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Advanced /// /// The type of the pixel. /// The source. - /// The span retuned from Pixel source + /// The span returned from Pixel source private static Span GetSpan(IPixelSource source) where TPixel : struct, IPixel => source.PixelBuffer.GetSpan(); @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Advanced /// The source. /// The row. /// - /// The span retuned from Pixel source + /// The span returned from Pixel source /// private static Span GetSpan(IPixelSource source, int row) where TPixel : struct, IPixel @@ -185,7 +185,7 @@ namespace SixLabors.ImageSharp.Advanced /// The source. /// The row. /// - /// The span retuned from Pixel source + /// The span returned from Pixel source /// private static Span GetSpan(Buffer2D source, int row) where TPixel : struct, IPixel diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 402aa79b5f..f07ccb03b4 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp /// /// Scales a value from an 8 bit to it's 16 bit equivalent. /// - /// The 8 bit compoonent value. + /// The 8 bit component value. /// The [MethodImpl(InliningOptions.ShortMethod)] public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index 0f1ce2ab6a..85c9f00748 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp var bVec = new Vector(256.0f / 255.0f); var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var magicInt = new Vector(1191182336); // reinterpreted value of 32768.0f var mask = new Vector(255); ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index a989cc8752..867e7b9de1 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp DebugGuard.IsTrue( ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, nameof(source), - $"length should be divisable by {shouldBeDivisibleBy}!"); + $"length should be divisible by {shouldBeDivisibleBy}!"); } [Conditional("DEBUG")] @@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp DebugGuard.IsTrue( ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, nameof(source), - $"length should be divisable by {shouldBeDivisibleBy}!"); + $"length should be divisible by {shouldBeDivisibleBy}!"); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index cea90cb45e..eb519f4214 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Looks up color values and builds the image from de-compressed RLE8 data. - /// Compresssed RLE8 stream is uncompressed by + /// Compressed RLE8 stream is uncompressed by /// /// The pixel format. /// The to assign the palette to. diff --git a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs index c44ca73f2e..219d37ca62 100644 --- a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs +++ b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs @@ -8,6 +8,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// internal interface IBmpDecoderOptions { - // added this for consistancy so we can add stuff as required, no options currently availible + // added this for consistency so we can add stuff as required, no options currently available } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index db512a0781..b8a270b3f5 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private GifGraphicControlExtension graphicsControlExtension; /// - /// The image desciptor. + /// The image descriptor. /// private GifImageDescriptor imageDescriptor; diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 17ee616072..a922f30117 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Formats.Gif internal sealed class GifEncoderCore { /// - /// Used for allocating memory during procesing operations. + /// Used for allocating memory during processing operations. /// private readonly MemoryAllocator memoryAllocator; @@ -421,7 +421,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteColorTable(QuantizedFrame image, Stream stream) where TPixel : struct, IPixel { - // The maximium number of colors for the bit depth + // The maximum number of colors for the bit depth int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; int pixelCount = image.Palette.Length; diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index e390dfd54c..34c353ec97 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Gif }; /// - /// The maximium number of bits/code. + /// The maximum number of bits/code. /// private const int MaxBits = 12; @@ -210,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// flush the packet to disk. /// /// The character to add. - /// The reference to the storage for packat accumulators + /// The reference to the storage for packet accumulators /// The stream to write to. [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddCharacter(byte c, ref byte accumulatorsRef, Stream stream) diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index 94191c1493..3cd289df76 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -16,12 +16,12 @@ namespace SixLabors.ImageSharp.Formats string Name { get; } /// - /// Gets the default mimetype that the image foramt uses + /// Gets the default mimetype that the image format uses /// string DefaultMimeType { get; } /// - /// Gets all the mimetypes that have been used by this image foramt. + /// Gets all the mimetypes that have been used by this image format. /// IEnumerable MimeTypes { get; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs index 5601a94366..60fec25d29 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs @@ -10,7 +10,7 @@ using System.Text; namespace SixLabors.ImageSharp.Formats.Jpeg.Components { /// - /// Represents a Jpeg block with coefficiens. + /// Represents a Jpeg block with coefficients. /// // ReSharper disable once InconsistentNaming internal unsafe struct Block8x8 : IEquatable @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } /// - /// Gets or sets a value in a row+coulumn of the 8x8 block + /// Gets or sets a value in a row+column of the 8x8 block /// /// The x position index in the row /// The column index @@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } /// - /// Calculate the total sum of absoulute differences of elements in 'a' and 'b'. + /// Calculate the total sum of absolute differences of elements in 'a' and 'b'. /// public static long TotalDifference(ref Block8x8 a, ref Block8x8 b) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 137a8029d8..2be5addc2f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -395,7 +395,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } /// - /// Scales the 16x16 region represented by the 4 source blocks to the 8x8 DST block. + /// Scales the 16x16 region represented by the 4 source blocks to the 8x8 DST block. /// /// The destination block. /// The source block. @@ -571,7 +571,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components // sign(dividend) = max(min(dividend, 1), -1) var sign = Vector4.Clamp(dividend, NegativeOne, Vector4.One); - // AlmostRound(dividend/divisor) = dividend/divisior + 0.5*sign(dividend) + // AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend) return (dividend / divisor) + (sign * Offset); } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index 1dc72aaf5b..23aa1acbe6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -32,11 +32,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// SIMD convert using buffers of sizes divisable by 8. + /// SIMD convert using buffers of sizes divisible by 8. /// internal static void ConvertCore(in ComponentValues values, Span result) { - DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisable by 8!"); + DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisible by 8!"); ref Vector4Pair yBase = ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component0)); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index 46644258b1..f0a70a6f38 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// SIMD convert using buffers of sizes divisable by 8. + /// SIMD convert using buffers of sizes divisible by 8. /// internal static void ConvertCore(in ComponentValues values, Span result) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 456636dc39..a44ebf89d1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters internal abstract partial class JpegColorConverter { /// - /// The avalilable converters + /// The available converters /// private static readonly JpegColorConverter[] Converters = { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index 24d570bf1c..9e134746bc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } // Figure F.15: generate decoding tables for bit-sequential decoding. - // Compute largest code + 1 for this size. preshifted as we needit later. + // Compute largest code + 1 for this size. preshifted as we need it later. Unsafe.Add(ref maxcodeRef, k) = code << (16 - k); code <<= 1; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs index dace78b337..1454bb5b12 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Size ImageSizeInPixels { get; } /// - /// Gets the number of coponents. + /// Gets the number of components. /// int ComponentCount { get; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs index f153ce062a..4bff492486 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// The minor version /// The units for the density values /// The horizontal pixel density - /// The veritcal pixel density + /// The vertical pixel density private JFifMarker(byte majorVersion, byte minorVersion, byte densityUnits, short xDensity, short yDensity) { Guard.MustBeGreaterThan(xDensity, 0, nameof(xDensity)); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs index 0108e30815..da4b2847b8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// - Dequantize /// - Applying IDCT /// - Level shift by +128, clip to [0, 255] - /// - Copy the resultin color values into 'destArea' scaling up the block by amount defined in + /// - Copy the resulting color values into 'destArea' scaling up the block by amount defined in /// /// The source block. /// The destination buffer area. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs index 57a53549f5..94ec600dd5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private int currentComponentRowInBlocks; /// - /// The size of the area in corrsponding to one 8x8 Jpeg block + /// The size of the area in corresponding to one 8x8 Jpeg block /// private readonly Size blockAreaSize; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index 5d232b5713..48abca2a4e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -755,7 +755,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder [MethodImpl(InliningOptions.ColdPath)] private void FillBuffer() { - // Attempt to load at least the minimum nbumber of required bits into the buffer. + // Attempt to load at least the minimum number of required bits into the buffer. // We fail to do so only if we hit a marker or reach the end of the input stream. do { @@ -912,7 +912,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } // If it's NOT a restart, then just bail, so we get corrupt data rather than no data. - // Reset the stream to before any bad markers to ensure we can read sucessive segments. + // Reset the stream to before any bad markers to ensure we can read successive segments. if (this.badMarker) { this.stream.Position = this.markerPosition; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs index a0cc9ee8e5..cb0810985e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// /// Initializes the YCbCr tables /// - /// The intialized + /// The initialized public static RgbToYCbCrTables Create() { RgbToYCbCrTables tables = default; diff --git a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs index 2e20da266b..c795ccc8b5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// FOR TESTING ONLY! - /// Gets or sets a value in a row+coulumn of the 8x8 block + /// Gets or sets a value in a row+column of the 8x8 block /// /// The x position index in the row /// The column index diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index ef73aab38f..67f665576b 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -51,12 +51,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private readonly byte[] markerBuffer = new byte[2]; /// - /// The DC HUffman tables + /// The DC Huffman tables /// private HuffmanTables dcHuffmanTables; /// - /// The AC HUffman tables + /// The AC Huffman tables /// private HuffmanTables acHuffmanTables; diff --git a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs index 07fc688d50..6ab0dd6576 100644 --- a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs +++ b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Chunks /// /// Constructs the PngPhysicalChunkData from the provided metadata. - /// If the resolution units are not in meters, they are automatically convereted. + /// If the resolution units are not in meters, they are automatically converted. /// /// The metadata. /// The constructed PngPhysicalChunkData instance. diff --git a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs index bd0b932056..5b650ac2a0 100644 --- a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs @@ -6,7 +6,7 @@ using System.Text; namespace SixLabors.ImageSharp.Formats.Png { /// - /// The optioas for decoding png images + /// The options for decoding png images /// internal interface IPngDecoderOptions { diff --git a/src/ImageSharp/IImageInfo.cs b/src/ImageSharp/IImageInfo.cs index 25d5ec7cab..6e64aa679a 100644 --- a/src/ImageSharp/IImageInfo.cs +++ b/src/ImageSharp/IImageInfo.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.MetaData; namespace SixLabors.ImageSharp { /// - /// Encapsulates properties that descibe basic image information including dimensions, pixel type information + /// Encapsulates properties that describe basic image information including dimensions, pixel type information /// and additional metadata /// public interface IImageInfo diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index e8d9ab7547..c2935bed93 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp public static partial class Image { /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. /// /// The pixel type @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. /// /// The pixel type @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. /// The memory is being observed, the caller remains responsible for managing it's lifecycle. /// @@ -79,15 +79,15 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. - /// The ownership of the is being transfered to the new instance, + /// The ownership of the is being transferred to the new instance, /// meaning that the caller is not allowed to dispose . /// It will be disposed together with the result image. /// /// The pixel type /// The - /// The that is being transfered to the image + /// The that is being transferred to the image /// The width of the memory image /// The height of the memory image /// The @@ -105,15 +105,15 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. - /// The ownership of the is being transfered to the new instance, + /// The ownership of the is being transferred to the new instance, /// meaning that the caller is not allowed to dispose . /// It will be disposed together with the result image. /// /// The pixel type /// The - /// The that is being transfered to the image + /// The that is being transferred to the image /// The width of the memory image /// The height of the memory image /// An instance @@ -128,14 +128,14 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. - /// The ownership of the is being transfered to the new instance, + /// The ownership of the is being transferred to the new instance, /// meaning that the caller is not allowed to dispose . /// It will be disposed together with the result image. /// /// The pixel type - /// The that is being transfered to the image + /// The that is being transferred to the image /// The width of the memory image /// The height of the memory image /// An instance diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index e579bec1a6..cbf93275c8 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp if (format is null) { var sb = new StringBuilder(); - sb.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); + sb.AppendLine($"Can't find a format that is associated with the file extension '{ext}'. Registered formats with there extensions include:"); foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats) { sb.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp if (encoder is null) { var sb = new StringBuilder(); - sb.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); + sb.AppendLine($"Can't find encoder for file extension '{ext}' using image format '{format.Name}'. Registered encoders include:"); foreach (KeyValuePair enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders) { sb.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 9d4c1ef0b3..178194b21e 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp public Image Clone() => this.Clone(this.configuration); /// - /// Clones the current image with the given configueation. + /// Clones the current image with the given configuration. /// /// The configuration providing initialization code which allows extending the library. /// Returns a new with all the same pixel data as the original. diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs index 71c27ca611..8f0427db27 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs @@ -39,15 +39,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// This profile provides the relevant information to perform a transformation - /// between colour encodings and the PCS. This type of profile is based on - /// modelling rather than device measurement or characterization data. + /// between color encodings and the PCS. This type of profile is based on + /// modeling rather than device measurement or characterization data. /// ColorSpace profiles may be embedded in images. /// ColorSpace = 0x73706163, // spac /// /// This profile represents abstract transforms and does not represent any - /// device model. Colour transformations using Abstract profiles are performed + /// device model. Color transformations using Abstract profiles are performed /// from PCS to PCS. Abstract profiles cannot be embedded in images. /// Abstract = 0x61627374, // abst @@ -55,8 +55,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// NamedColor profiles can be thought of as sibling profiles to device profiles. /// For a given device there would be one or more device profiles to handle - /// process colour conversions and one or more named colour profiles to handle - /// named colours. + /// process color conversions and one or more named color profiles to handle + /// named colors. /// NamedColor = 0x6E6D636C, // nmcl } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs index 3758be34b7..1e9ec18e89 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs @@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc NotEmbedded = 0, /// - /// Profile cannot be used independently of the embedded colour data + /// Profile cannot be used independently of the embedded color data /// NotIndependent = 1 << 1, /// - /// Profile can be used independently of the embedded colour data + /// Profile can be used independently of the embedded color data /// Independent = 0, } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs index 82b2969003..61d34dca10 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs @@ -19,18 +19,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc Unknown, /// - /// A2B0 - This tag defines a colour transform from Device, Colour Encoding or PCS, to PCS, or a colour transform + /// A2B0 - This tag defines a color transform from Device, Color Encoding or PCS, to PCS, or a color transform /// from Device 1 to Device 2, using lookup table tag element structures /// AToB0 = 0x41324230, /// - /// A2B2 - This tag describes the colour transform from Device or Colour Encoding to PCS using lookup table tag element structures + /// A2B2 - This tag describes the color transform from Device or Color Encoding to PCS using lookup table tag element structures /// AToB1 = 0x41324231, /// - /// A2B2 - This tag describes the colour transform from Device or Colour Encoding to PCS using lookup table tag element structures + /// A2B2 - This tag describes the color transform from Device or Color Encoding to PCS using lookup table tag element structures /// AToB2 = 0x41324232, @@ -46,40 +46,40 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc BlueTrc = 0x62545243, /// - /// B2A0 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures + /// B2A0 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures /// BToA0 = 0x42324130, /// - /// B2A1 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures. + /// B2A1 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures. /// BToA1 = 0x42324131, /// - /// B2A2 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures. + /// B2A2 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures. /// BToA2 = 0x42324132, /// - /// B2D0 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D0 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA0 tag. /// BToD0 = 0x42324430, /// - /// B2D1 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D1 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA1 tag. /// BToD1 = 0x42324431, /// - /// B2D2 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D2 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA2 tag. /// BToD2 = 0x42324432, /// - /// B2D3 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D3 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA1 tag. /// BToD3 = 0x42324433, @@ -97,8 +97,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc CharTarget = 0x74617267, /// - /// chad - This tag contains a matrix, which shall be invertible, and which converts an nCIEXYZ colour, measured using the actual illumination - /// conditions and relative to the actual adopted white, to an nCIEXYZ colour relative to the PCS adopted white + /// chad - This tag contains a matrix, which shall be invertible, and which converts an nCIEXYZ color, measured using the actual illumination + /// conditions and relative to the actual adopted white, to an nCIEXYZ color relative to the PCS adopted white /// ChromaticAdaptation = 0x63686164, @@ -166,33 +166,33 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc DeviceSettings = 0x64657673, /// - /// D2B0 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B0 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB0 tag /// DToB0 = 0x44324230, /// - /// D2B1 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B1 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB1 tag /// DToB1 = 0x44324230, /// - /// D2B2 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B2 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB1 tag /// DToB2 = 0x44324230, /// - /// D2B3 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B3 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB1 tag /// DToB3 = 0x44324230, /// /// gamt - This tag provides a table in which PCS values are the input and a single - /// output value for each input value is the output. If the output value is 0, the PCS colour is in-gamut. - /// If the output is non-zero, the PCS colour is out-of-gamut + /// output value for each input value is the output. If the output value is 0, the PCS color is in-gamut. + /// If the output is non-zero, the PCS color is out-of-gamut /// Gamut = 0x67616D74, @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc GreenTrc = 0x67545243, /// - /// lumi - This tag contains the absolute luminance of emissive devices in candelas per square metre as described by the Y channel. + /// lumi - This tag contains the absolute luminance of emissive devices in candelas per square meter as described by the Y channel. /// Luminance = 0x6C756d69, @@ -240,8 +240,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc NamedColor = 0x6E636f6C, /// - /// ncl2 - This tag contains the named colour information providing a PCS and optional device representation - /// for a list of named colours. + /// ncl2 - This tag contains the named color information providing a PCS and optional device representation + /// for a list of named colors. /// NamedColor2 = 0x6E636C32, diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs index e0504b24cb..7cb9c00f39 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs @@ -10,11 +10,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc { /// /// In perceptual transforms the PCS values represent hypothetical - /// measurements of a colour reproduction on the reference reflective + /// measurements of a color reproduction on the reference reflective /// medium. By extension, for the perceptual intent, the PCS represents /// the appearance of that reproduction as viewed in the reference viewing /// environment by a human observer adapted to that environment. The exact - /// colour rendering of the perceptual intent is vendor specific. + /// color rendering of the perceptual intent is vendor specific. /// Perceptual = 0, @@ -27,15 +27,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc MediaRelativeColorimetric = 1, /// - /// The exact colour rendering of the saturation intent is vendor + /// The exact color rendering of the saturation intent is vendor /// specific and involves compromises such as trading off - /// preservation of hue in order to preserve the vividness of pure colours. + /// preservation of hue in order to preserve the vividness of pure colors. /// Saturation = 2, /// /// Transformations for this intent shall leave the chromatically - /// adapted nCIEXYZ tristimulus values of the in-gamut colours unchanged. + /// adapted nCIEXYZ tristimulus values of the in-gamut colors unchanged. /// AbsoluteColorimetric = 3, } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs index 1493ecc6bb..ad0db4df93 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// This is an optional tag which specifies the laydown order in which colorants /// will be printed on an n-colorant device. The laydown order may be the same /// as the channel generation order listed in the colorantTableTag or the channel - /// order of a colour encoding type such as CMYK, in which case this tag is not + /// order of a color encoding type such as CMYK, in which case this tag is not /// needed. When this is not the case (for example, ink-towers sometimes use /// the order KCMY), this tag may be used to specify the laydown order of the /// colorants @@ -59,25 +59,25 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc DateTime = 0x6474696D, /// - /// This structure represents a colour transform using tables with 16-bit + /// This structure represents a color transform using tables with 16-bit /// precision. This type contains four processing elements: a 3 × 3 matrix - /// (which shall be the identity matrix unless the input colour space is + /// (which shall be the identity matrix unless the input color space is /// PCSXYZ), a set of one-dimensional input tables, a multi-dimensional /// lookup table, and a set of one-dimensional output tables /// Lut16 = 0x6D667432, /// - /// This structure represents a colour transform using tables of 8-bit + /// This structure represents a color transform using tables of 8-bit /// precision. This type contains four processing elements: a 3 × 3 matrix - /// (which shall be the identity matrix unless the input colour space is + /// (which shall be the identity matrix unless the input color space is /// PCSXYZ), a set of one-dimensional input tables, a multi-dimensional /// lookup table, and a set of one-dimensional output tables. /// Lut8 = 0x6D667431, /// - /// This structure represents a colour transform. The type contains up + /// This structure represents a color transform. The type contains up /// to five processing elements which are stored in the AToBTag tag /// in the following order: a set of one-dimensional curves, a 3 × 3 /// matrix with offset terms, a set of one-dimensional curves, a @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc LutAToB = 0x6D414220, /// - /// This structure represents a colour transform. The type contains + /// This structure represents a color transform. The type contains /// up to five processing elements which are stored in the BToATag /// in the following order: a set of one-dimensional curves, a 3 × 3 /// matrix with offset terms, a set of one-dimensional curves, a @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc MultiLocalizedUnicode = 0x6D6C7563, /// - /// This structure represents a colour transform, containing a sequence + /// This structure represents a color transform, containing a sequence /// of processing elements. The processing elements contained in the /// structure are defined in the structure itself, allowing for a flexible /// structure. Currently supported processing elements are: a set of one @@ -123,15 +123,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc MultiProcessElements = 0x6D706574, /// - /// This type is a count value and array of structures that provide colour - /// coordinates for colour names. For each named colour, a PCS and optional - /// device representation of the colour are given. Both representations are + /// This type is a count value and array of structures that provide color + /// coordinates for color names. For each named color, a PCS and optional + /// device representation of the color are given. Both representations are /// 16-bit values and PCS values shall be relative colorimetric. The device - /// representation corresponds to the header’s "data colour space" field. + /// representation corresponds to the header’s "data color space" field. /// This representation should be consistent with the "number of device /// coordinates" field in the namedColor2Type. If this field is 0, device /// coordinates are not provided. The PCS representation corresponds to the - /// header's PCS field. The PCS representation is always provided. Colour + /// header's PCS field. The PCS representation is always provided. Color /// names are fixed-length, 32-byte fields including null termination. In /// order to maintain maximum portability, it is strongly recommended that /// special characters of the 7-bit ASCII set not be used. @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// so that corrections can be made for variation in the device without /// having to produce a new profile. The mechanism can be used by applications /// to allow users with relatively inexpensive and readily available - /// instrumentation to apply corrections to individual output colour + /// instrumentation to apply corrections to individual output color /// channels in order to achieve consistent results. /// ResponseCurveSet16 = 0x72637332, diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index 2ed3164097..2572b32933 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The hexadecimal representation of the combined color components arranged /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. /// - /// Returns a that represents the color defined by the provided RGBA heax string. + /// Returns a that represents the color defined by the provided RGBA hex string. public static TPixel FromHex(string hex) { Guard.NotNullOrWhiteSpace(hex, nameof(hex)); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index f4eb19be33..115dd7a43d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the - // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm. + // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 algorithm. // One of the requirements of FromScaledVector4/ToScaledVector4 is that it unaware of this and // packs/unpacks the pixel without and conversion so we employ custom methods do do this. if (typeof(TDestinationPixel) == typeof(Gray16)) diff --git a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs index 55a94fc81e..12ec389b06 100644 --- a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils // packedRgba = [aa bb gg rr] // tmp1 = [aa 00 gg 00] // tmp2 = [00 bb 00 rr] - // tmp3=ROTL(16, tmp2) = [00 rr 00 bb] + // tmp3=ROTL(16, tmp2) = [00 rr 00 bb] // tmp1 + tmp3 = [aa rr gg bb] uint tmp1 = packedRgba & 0xFF00FF00; uint tmp2 = packedRgba & 0x00FF00FF; diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs index 7c57fe4fbd..5609e606d8 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); - // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers, + // 'destVectors' and 'lastQuarterOfDestBuffer' are overlapping buffers, // but we are always reading/writing at different positions: SimdUtils.BulkConvertByteToNormalizedFloat( MemoryMarshal.Cast(lastQuarterOfDestBuffer), From 99f06f7657eee5e186a683b0c51b277a3335d7ea Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:07:06 +0100 Subject: [PATCH 163/238] fix typo in comment --- src/ImageSharp/Formats/Png/Filters/PaethFilter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs index 4ffc39bdbd..4cd61e043d 100644 --- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); // Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) - int offset = bytesPerPixel + 1; // Add one bcause x starts at one. + int offset = bytesPerPixel + 1; // Add one because x starts at one. int x = 1; for (; x < offset; x++) { From e42cf0cd6993c2998f18f1d494a9920bcd413bd2 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 5 Nov 2018 16:55:48 -0600 Subject: [PATCH 164/238] ImageSharp-762_Aot-compiling: whitespace cleanup --- src/ImageSharp/Advanced/AotCompiler.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Advanced/AotCompiler.cs b/src/ImageSharp/Advanced/AotCompiler.cs index 1c7f12ef7b..406c162ad5 100644 --- a/src/ImageSharp/Advanced/AotCompiler.cs +++ b/src/ImageSharp/Advanced/AotCompiler.cs @@ -63,9 +63,9 @@ namespace SixLabors.ImageSharp.Advanced /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT - /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on - /// iOS so it bombs out. - /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the + /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on + /// iOS so it bombs out. + /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! /// /// The pixel format. From 45fd99983a2db2f47ee240ee9e913a5b48b28df8 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 5 Nov 2018 19:21:16 -0800 Subject: [PATCH 165/238] Fix infinate loop when a GIF prematurely terminates in Skip --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 29 ++++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index b8a270b3f5..bfa91416aa 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -142,8 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadApplicationExtension(); break; case GifConstants.PlainTextLabel: - int plainLength = stream.ReadByte(); - this.Skip(plainLength); // Not supported by any known decoder. + this.SkipBlock(); // Not supported by any known decoder. break; } } @@ -190,9 +189,7 @@ namespace SixLabors.ImageSharp.Formats.Gif switch (stream.ReadByte()) { case GifConstants.GraphicControlLabel: - - // Skip graphic control extension block - this.Skip(0); + this.SkipBlock(); // Skip graphic control extension block break; case GifConstants.CommentLabel: this.ReadComments(); @@ -201,8 +198,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadApplicationExtension(); break; case GifConstants.PlainTextLabel: - int plainLength = stream.ReadByte(); - this.Skip(plainLength); // Not supported by any known decoder. + this.SkipBlock(); // Not supported by any known decoder. break; } } @@ -288,24 +284,27 @@ namespace SixLabors.ImageSharp.Formats.Gif // Could be XMP or something else not supported yet. // Back up and skip. this.stream.Position -= appLength + 1; - this.Skip(appLength); + this.SkipBlock(appLength); return; } - this.Skip(appLength); // Not supported by any known decoder. + this.SkipBlock(appLength); // Not supported by any known decoder. } /// - /// Skips the designated number of bytes in the stream. + /// Skips over a block or reads its terminator. + /// The length of the block to skip. /// - /// The number of bytes to skip. - private void Skip(int length) + private void SkipBlock(int blockSize = 0) { - this.stream.Skip(length); + if (blockSize > 0) + { + this.stream.Skip(blockSize); + } int flag; - while ((flag = this.stream.ReadByte()) != 0) + while ((flag = this.stream.ReadByte()) > 0) { this.stream.Skip(flag); } @@ -370,7 +369,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, this.imageDescriptor); // Skip any remaining blocks - this.Skip(0); + this.SkipBlock(); } finally { From 74e3a3505cead90b4b2c10cfc905d4a7bb8a5709 Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Tue, 6 Nov 2018 09:46:14 -0600 Subject: [PATCH 166/238] ImageSharp-762_Aot-compiling: clean up AotGetPalette method --- .../Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 8f688e8387..dd56375f63 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } - internal TPixel[] AotGetPalette() => this.octree.Palletize(this.colors); + internal TPixel[] AotGetPalette() => this.GetPalette(); /// protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors); From fdb45dda5e350e342d67af9e30c112c98d8e6aec Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 6 Nov 2018 08:40:08 -0800 Subject: [PATCH 167/238] Add test coverage for #770 --- .../ImageSharp.Sandbox46.csproj | 2 +- .../Formats/Gif/GifDecoderTests.cs | 33 +++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index bb559b70dd..4d7b7de759 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -11,7 +11,7 @@ James Jackson-South and contributors James Jackson-South SixLabors.ImageSharp.Sandbox46 - 7.2 + 7.3 diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 6d2a74c03b..5bfbb058be 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -1,20 +1,20 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Collections.Generic; +using System.IO; using System.Text; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; -using System.IO; -using SixLabors.ImageSharp.Advanced; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Gif { - using System.Collections.Generic; - using SixLabors.ImageSharp.MetaData; - using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; - public class GifDecoderTests { private const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.RgbaVector | PixelTypes.Argb32; @@ -70,6 +70,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif } } + [Fact] + public unsafe void Decode_NonTerminatedFinalFrame() + { + var testFile = TestFile.Create(TestImages.Gif.Rings); + + int length = testFile.Bytes.Length - 2; + + fixed (byte* data = testFile.Bytes.AsSpan(0, length)) + { + using (var stream = new UnmanagedMemoryStream(data, length)) + { + var decoder = new GifDecoder(); + + using (Image image = decoder.Decode(Configuration.Default, stream)) + { + Assert.Equal((200, 200), (image.Width, image.Height)); + } + } + } + } + [Theory] [MemberData(nameof(RatioFiles))] public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) From dfc926e5692cadfc5c5b0d3b59cdcea9225ba7fe Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 6 Nov 2018 17:27:21 +0000 Subject: [PATCH 168/238] Better Rotate --- .../Transforms/AffineTransformProcessor.cs | 204 ++++----------- .../Transforms/AffineTransformProcessorOld.cs | 239 ++++++++++++++++++ .../CenteredAffineTransformProcessor.cs | 2 +- .../Processors/Transforms/RotateProcessor.cs | 16 +- .../Transforms/TransformKernelMap.cs | 188 ++++++++++++++ .../Processors/Transforms/TransformUtils.cs | 121 +++++++++ .../Processing/TransformExtensions.cs | 6 +- 7 files changed, 611 insertions(+), 165 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs create mode 100644 src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs create mode 100644 src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index e12b91eab9..edddab1811 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -5,13 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -20,29 +16,42 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides the base methods to perform affine transforms on an image. /// /// The pixel format. - internal class AffineTransformProcessor : InterpolatedTransformProcessorBase + internal class AffineTransformProcessor : TransformProcessorBase where TPixel : struct, IPixel { + private readonly Rectangle transformedRectangle; + /// /// Initializes a new instance of the class. /// /// The transform matrix /// The sampler to perform the transform operation. - /// The target dimensions to constrain the transformed image to. - public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size targetDimensions) - : base(sampler) + /// The source image size + public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize) { + Guard.NotNull(sampler, nameof(sampler)); + this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = targetDimensions; + this.transformedRectangle = TransformUtils.GetTransformedRectangle( + new Rectangle(Point.Empty, sourceSize), + matrix); + + // We want to resize the canvas here taking into account any translations. + this.TargetDimensions = new Size(this.transformedRectangle.Right, this.transformedRectangle.Bottom); } /// - /// Gets the matrix used to supply the affine transform + /// Gets the sampler to perform interpolation of the transform operation. + /// + public IResampler Sampler { get; } + + /// + /// Gets the matrix used to supply the affine transform. /// public Matrix3x2 TransformMatrix { get; } /// - /// Gets the target dimensions to constrain the transformed image to + /// Gets the target dimensions to constrain the transformed image to. /// public Size TargetDimensions { get; } @@ -68,13 +77,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int width = this.TargetDimensions.Width; Rectangle sourceBounds = source.Bounds(); - var targetBounds = new Rectangle(0, 0, width, height); - - // Since could potentially be resizing the canvas we might need to re-calculate the matrix - Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); + var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. - Matrix3x2.Invert(matrix, out matrix); + Matrix3x2.Invert(this.TransformMatrix, out Matrix3x2 matrix); if (this.Sampler is NearestNeighborResampler) { @@ -82,158 +88,52 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms targetBounds, configuration, rows => + { + for (int y = rows.Min; y < rows.Max; y++) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span destRow = destination.GetPixelRowSpan(y); + Span destRow = destination.GetPixelRowSpan(y); - for (int x = 0; x < width; x++) + for (int x = 0; x < width; x++) + { + var point = Point.Transform(new Point(x, y), matrix); + if (sourceBounds.Contains(point.X, point.Y)) { - var point = Point.Transform(new Point(x, y), matrix); - if (sourceBounds.Contains(point.X, point.Y)) - { - destRow[x] = source[point.X, point.Y]; - } + destRow[x] = source[point.X, point.Y]; } } - }); + } + }); return; } - int maxSourceX = source.Width - 1; - int maxSourceY = source.Height - 1; - (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); - (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - float xScale = xRadiusScale.scale; - float yScale = yRadiusScale.scale; - var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); - IResampler sampler = this.Sampler; - var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); - int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); - int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); - - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) - using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) + using (var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler)) { - ParallelHelper.IterateRows( + ParallelHelper.IterateRowsWithTempBuffer( targetBounds, configuration, - rows => + (rows, vectorBuffer) => + { + Span vectorSpan = vectorBuffer.Span; + for (int y = rows.Min; y < rows.Max; y++) { - for (int y = rows.Min; y < rows.Max; y++) - { - ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); - ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); + Span targetRowSpan = destination.GetPixelRowSpan(y); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan, vectorSpan); + ref float ySpanRef = ref kernel.GetYStartReference(y); + ref float xSpanRef = ref kernel.GetXStartReference(y); - for (int x = 0; x < width; x++) - { - // Use the single precision position to calculate correct bounding pixels - // otherwise we get rogue pixels outside of the bounds. - var point = Vector2.Transform(new Vector2(x, y), matrix); - - // Clamp sampling pixel radial extents to the source image edges - Vector2 maxXY = point + radius; - Vector2 minXY = point - radius; - - // max, maxY, minX, minY - var extents = new Vector4( - MathF.Floor(maxXY.X + .5F), - MathF.Floor(maxXY.Y + .5F), - MathF.Ceiling(minXY.X - .5F), - MathF.Ceiling(minXY.Y - .5F)); - - int right = (int)extents.X; - int bottom = (int)extents.Y; - int left = (int)extents.Z; - int top = (int)extents.W; - - extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); - - int maxX = (int)extents.X; - int maxY = (int)extents.Y; - int minX = (int)extents.Z; - int minY = (int)extents.W; - - if (minX == maxX || minY == maxY) - { - continue; - } - - // It appears these have to be calculated on-the-fly. - // Precalculating transformed weights would require prior knowledge of every transformed pixel location - // since they can be at sub-pixel positions on both axis. - // I've optimized where I can but am always open to suggestions. - if (yScale > 1 && xScale > 1) - { - CalculateWeightsDown( - top, - bottom, - minY, - maxY, - point.Y, - sampler, - yScale, - ref ySpanRef, - yLength); - - CalculateWeightsDown( - left, - right, - minX, - maxX, - point.X, - sampler, - xScale, - ref xSpanRef, - xLength); - } - else - { - CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); - CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); - } - - // Now multiply the results against the offsets - Vector4 sum = Vector4.Zero; - for (int yy = 0, j = minY; j <= maxY; j++, yy++) - { - float yWeight = Unsafe.Add(ref ySpanRef, yy); - - for (int xx = 0, i = minX; i <= maxX; i++, xx++) - { - float xWeight = Unsafe.Add(ref xSpanRef, xx); - - // Values are first premultiplied to prevent darkening of edge pixels - var current = source[i, j].ToVector4(); - Vector4Utils.Premultiply(ref current); - sum += current * xWeight * yWeight; - } - } - - ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); - - // Reverse the premultiplication - Vector4Utils.UnPremultiply(ref sum); - dest.FromVector4(sum); - } + for (int x = 0; x < width; x++) + { + // Use the single precision position to calculate correct bounding pixels + // otherwise we get rogue pixels outside of the bounds. + var point = Vector2.Transform(new Vector2(x, y), matrix); + kernel.Convolve(point, x, ref ySpanRef, ref xSpanRef, source.PixelBuffer, vectorSpan); } - }); + + PixelOperations.Instance.FromVector4(configuration, vectorSpan, targetRowSpan); + } + }); } } - - /// - /// Gets a transform matrix adjusted for final processing based upon the target image bounds. - /// - /// The source image bounds. - /// The destination image bounds. - /// - /// The . - /// - protected virtual Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - => this.TransformMatrix; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs new file mode 100644 index 0000000000..5891afd9a6 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs @@ -0,0 +1,239 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Provides the base methods to perform affine transforms on an image. + /// + /// The pixel format. + internal class AffineTransformProcessorOld : InterpolatedTransformProcessorBase + where TPixel : struct, IPixel + { + /// + /// Initializes a new instance of the class. + /// + /// The transform matrix + /// The sampler to perform the transform operation. + /// The target dimensions to constrain the transformed image to. + public AffineTransformProcessorOld(Matrix3x2 matrix, IResampler sampler, Size targetDimensions) + : base(sampler) + { + this.TransformMatrix = matrix; + this.TargetDimensions = targetDimensions; + } + + /// + /// Gets the matrix used to supply the affine transform + /// + public Matrix3x2 TransformMatrix { get; } + + /// + /// Gets the target dimensions to constrain the transformed image to + /// + public Size TargetDimensions { get; } + + /// + protected override Image CreateDestination(Image source, Rectangle sourceRectangle) + { + // We will always be creating the clone even for mutate because we may need to resize the canvas + IEnumerable> frames = + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); + + // Use the overload to prevent an extra frame being added + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + } + + /// + protected override void OnFrameApply( + ImageFrame source, + ImageFrame destination, + Rectangle sourceRectangle, + Configuration configuration) + { + int height = this.TargetDimensions.Height; + int width = this.TargetDimensions.Width; + + Rectangle sourceBounds = source.Bounds(); + var targetBounds = new Rectangle(0, 0, width, height); + + // Since could potentially be resizing the canvas we might need to re-calculate the matrix + Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); + + // Convert from screen to world space. + Matrix3x2.Invert(matrix, out matrix); + + if (this.Sampler is NearestNeighborResampler) + { + ParallelHelper.IterateRows( + targetBounds, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span destRow = destination.GetPixelRowSpan(y); + + for (int x = 0; x < width; x++) + { + var point = Point.Transform(new Point(x, y), matrix); + if (sourceBounds.Contains(point.X, point.Y)) + { + destRow[x] = source[point.X, point.Y]; + } + } + } + }); + + return; + } + + int maxSourceX = source.Width - 1; + int maxSourceY = source.Height - 1; + (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); + (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); + float xScale = xRadiusScale.scale; + float yScale = yRadiusScale.scale; + var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); + IResampler sampler = this.Sampler; + var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); + int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); + int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); + + MemoryAllocator memoryAllocator = configuration.MemoryAllocator; + + using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) + using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) + { + ParallelHelper.IterateRows( + targetBounds, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); + ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); + ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); + + for (int x = 0; x < width; x++) + { + // Use the single precision position to calculate correct bounding pixels + // otherwise we get rogue pixels outside of the bounds. + var point = Vector2.Transform(new Vector2(x, y), matrix); + + // Clamp sampling pixel radial extents to the source image edges + Vector2 maxXY = point + radius; + Vector2 minXY = point - radius; + + // max, maxY, minX, minY + var extents = new Vector4( + MathF.Floor(maxXY.X + .5F), + MathF.Floor(maxXY.Y + .5F), + MathF.Ceiling(minXY.X - .5F), + MathF.Ceiling(minXY.Y - .5F)); + + int right = (int)extents.X; + int bottom = (int)extents.Y; + int left = (int)extents.Z; + int top = (int)extents.W; + + extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); + + int maxX = (int)extents.X; + int maxY = (int)extents.Y; + int minX = (int)extents.Z; + int minY = (int)extents.W; + + if (minX == maxX || minY == maxY) + { + continue; + } + + // It appears these have to be calculated on-the-fly. + // Precalculating transformed weights would require prior knowledge of every transformed pixel location + // since they can be at sub-pixel positions on both axis. + // I've optimized where I can but am always open to suggestions. + if (yScale > 1 && xScale > 1) + { + CalculateWeightsDown( + top, + bottom, + minY, + maxY, + point.Y, + sampler, + yScale, + ref ySpanRef, + yLength); + + CalculateWeightsDown( + left, + right, + minX, + maxX, + point.X, + sampler, + xScale, + ref xSpanRef, + xLength); + } + else + { + CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); + CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); + } + + // Now multiply the results against the offsets + Vector4 sum = Vector4.Zero; + for (int yy = 0, j = minY; j <= maxY; j++, yy++) + { + float yWeight = Unsafe.Add(ref ySpanRef, yy); + + for (int xx = 0, i = minX; i <= maxX; i++, xx++) + { + float xWeight = Unsafe.Add(ref xSpanRef, xx); + + // Values are first premultiplied to prevent darkening of edge pixels + var current = source[i, j].ToVector4(); + Vector4Utils.Premultiply(ref current); + sum += current * xWeight * yWeight; + } + } + + ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); + + // Reverse the premultiplication + Vector4Utils.UnPremultiply(ref sum); + dest.FromVector4(sum); + } + } + }); + } + } + + /// + /// Gets a transform matrix adjusted for final processing based upon the target image bounds. + /// + /// The source image bounds. + /// The destination image bounds. + /// + /// The . + /// + protected virtual Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) + => this.TransformMatrix; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs index adaee17665..82614dc8c2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// A base class that provides methods to allow the automatic centering of affine transforms /// /// The pixel format. - internal abstract class CenteredAffineTransformProcessor : AffineTransformProcessor + internal abstract class CenteredAffineTransformProcessor : AffineTransformProcessorOld where TPixel : struct, IPixel { /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 2ad626755c..cbf82cc9b0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -2,12 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -16,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides methods that allow the rotating of images. /// /// The pixel format. - internal class RotateProcessor : CenteredAffineTransformProcessor + internal class RotateProcessor : AffineTransformProcessor where TPixel : struct, IPixel { /// @@ -36,10 +34,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the rotating operation. /// The source image size public RotateProcessor(float degrees, IResampler sampler, Size sourceSize) - : base(Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty), sampler, sourceSize) - { - this.Degrees = degrees; - } + : base( + TransformUtils.CreateCenteredRotationMatrixDegrees(degrees, sourceSize), + sampler, + sourceSize) + => this.Degrees = degrees; /// /// Gets the angle of rotation in degrees. @@ -84,7 +83,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The private static float WrapDegrees(float degrees) { - degrees = degrees % 360; + degrees %= 360; while (degrees < 0) { @@ -223,7 +222,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int newX = height - y - 1; for (int x = 0; x < width; x++) { - // TODO: Optimize this: if (destinationBounds.Contains(newX, x)) { destination[newX, x] = sourceRow[x]; diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs new file mode 100644 index 0000000000..5acc7213cb --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs @@ -0,0 +1,188 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +// TODO: It would be great if we could somehow optimize this to calculate the weights once. +// currently we cannot do that as we are calulating the weight of the transformed point dimension +// not the point in the original image. +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains the methods required to calculate kernel sampling weights on-the-fly. + /// + internal class TransformKernelMap : IDisposable + { + private readonly Buffer2D yBuffer; + private readonly Buffer2D xBuffer; + private readonly float yScale; + private readonly float xScale; + private readonly int yLength; + private readonly int xLength; + private readonly Vector2 extents; + private Vector4 maxSourceExtents; + private readonly IResampler sampler; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration. + /// The source size. + /// The destination size. + /// The sampler. + public TransformKernelMap(Configuration configuration, Size source, Size destination, IResampler sampler) + { + this.sampler = sampler; + (float radius, float scale) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); + (float radius, float scale) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); + + this.yScale = yRadiusScale.scale; + this.xScale = xRadiusScale.scale; + this.extents = new Vector2(xRadiusScale.radius, yRadiusScale.radius); + this.xLength = (int)MathF.Ceiling((this.extents.X * 2) + 2); + this.yLength = (int)MathF.Ceiling((this.extents.Y * 2) + 2); + + // We use 2D buffers so that we can access the weight spans in parallel. + this.yBuffer = configuration.MemoryAllocator.Allocate2D(this.yLength, destination.Height); + this.xBuffer = configuration.MemoryAllocator.Allocate2D(this.xLength, destination.Height); + + int maxX = source.Width - 1; + int maxY = source.Height - 1; + this.maxSourceExtents = new Vector4(maxX, maxY, maxX, maxY); + } + + /// + /// Gets a reference to the first item of the y window. + /// + /// The reference to the first item of the window. + [MethodImpl(InliningOptions.ShortMethod)] + public ref float GetYStartReference(int y) + => ref MemoryMarshal.GetReference(this.yBuffer.GetRowSpan(y)); + + /// + /// Gets a reference to the first item of the x window. + /// + /// The reference to the first item of the window. + [MethodImpl(InliningOptions.ShortMethod)] + public ref float GetXStartReference(int y) + => ref MemoryMarshal.GetReference(this.xBuffer.GetRowSpan(y)); + + public void Convolve( + Vector2 transformedPoint, + int column, + ref float ySpanRef, + ref float xSpanRef, + Buffer2D sourcePixels, + Span targetRow) + where TPixel : struct, IPixel + { + // Clamp sampling pixel radial extents to the source image edges + Vector2 minXY = transformedPoint - this.extents; + Vector2 maxXY = transformedPoint + this.extents; + + // minX, minY, maxX, maxY + var extents = new Vector4( + MathF.Ceiling(minXY.X - .5F), + MathF.Ceiling(minXY.Y - .5F), + MathF.Floor(maxXY.X + .5F), + MathF.Floor(maxXY.Y + .5F)); + + int left = (int)extents.X; + int top = (int)extents.Y; + int right = (int)extents.Z; + int bottom = (int)extents.W; + + extents = Vector4.Clamp(extents, Vector4.Zero, this.maxSourceExtents); + + int minX = (int)extents.X; + int minY = (int)extents.Y; + int maxX = (int)extents.Z; + int maxY = (int)extents.W; + + if (minX == maxX || minY == maxY) + { + return; + } + + // TODO: Get Anton to use his superior brain on this one. + // It looks to me like we're calculating the same weights over and over again + // since min(X+Y) and max(X+Y) are the same distance apart. + this.CalculateWeights(minY, maxY, maxY - minY, transformedPoint.Y, ref ySpanRef); + this.CalculateWeights(minX, maxX, maxX - minX, transformedPoint.X, ref xSpanRef); + + Vector4 sum = Vector4.Zero; + for (int kernelY = 0, y = minY; y <= maxY; y++, kernelY++) + { + float yWeight = Unsafe.Add(ref ySpanRef, kernelY); + + for (int kernelX = 0, x = minX; x <= maxX; x++, kernelX++) + { + float xWeight = Unsafe.Add(ref xSpanRef, kernelX); + + // Values are first premultiplied to prevent darkening of edge pixels. + var current = sourcePixels[x, y].ToVector4(); + Vector4Utils.Premultiply(ref current); + sum += current * xWeight * yWeight; + } + } + + // Reverse the premultiplication + Vector4Utils.UnPremultiply(ref sum); + targetRow[column] = sum; + } + + /// + /// Calculated the normalized weights for the given point. + /// + /// The minimum sampling offset + /// The maximum sampling offset + /// The length of the weights collection + /// The transformed point dimension + /// The reference to the collection of weights + [MethodImpl(InliningOptions.ShortMethod)] + private void CalculateWeights(int min, int max, int length, float point, ref float weightsRef) + { + float sum = 0; + for (int x = 0, i = min; i <= max; i++, x++) + { + float weight = this.sampler.GetValue(i - point); + sum += weight; + Unsafe.Add(ref weightsRef, x) = this.sampler.GetValue(i - point); + } + + // TODO: Do we need this? Check what happens when we scale an image down. + // if (sum > 0) + // { + // for (int i = 0; i < length; i++) + // { + // ref float wRef = ref Unsafe.Add(ref weightsRef, i); + // wRef /= sum; + // } + // } + } + + private (float radius, float scale) GetSamplingRadius(int sourceSize, int destinationSize) + { + float scale = (float)sourceSize / destinationSize; + + if (scale < 1F) + { + scale = 1F; + } + + return (MathF.Ceiling(scale * this.sampler.Radius), scale); + } + + public void Dispose() + { + this.yBuffer?.Dispose(); + this.xBuffer?.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs new file mode 100644 index 0000000000..7d03502499 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -0,0 +1,121 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains utility methods for working with transforms. + /// + public static class TransformUtils + { + /// + /// Creates a centered rotation matrix using the given rotation in degrees and the source size. + /// + /// The amount of rotation, in degrees. + /// The source image size. + /// The . + public static Matrix3x2 CreateCenteredRotationMatrixDegrees(float degrees, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty)); + + /// + /// Gets the centered transform matrix based upon the source and destination rectangles. + /// + /// The source image bounds. + /// The transformation matrix. + /// The + public static Matrix3x2 CreateCenteredTransformMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) + { + Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); + + // We invert the matrix to handle the transformation from screen to world space. + // This ensures scaling matrices are correct. + Matrix3x2.Invert(matrix, out Matrix3x2 inverted); + + var translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); + var translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); + + // Translate back to world space. + Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); + + return centered; + } + + /// + /// Gets the centered transform matrix based upon the source and destination rectangles. + /// + /// The source image bounds. + /// The destination image bounds. + /// The transformation matrix. + /// The + public static Matrix3x2 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix3x2 matrix) + { + // We invert the matrix to handle the transformation from screen to world space. + // This ensures scaling matrices are correct. + Matrix3x2.Invert(matrix, out Matrix3x2 inverted); + + var translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); + var translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); + + // Translate back to world space. + Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); + + return centered; + } + + /// + /// Returns the rectangle bounds relative to the source for the given transformation matrix. + /// + /// The source rectangle. + /// The transformation matrix. + /// + /// The . + /// + public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) + { + Rectangle transformed = GetTransformedRectangle(rectangle, matrix); + + // TODO: Check this. + return new Rectangle(0, 0, transformed.Width, transformed.Height); + } + + /// + /// Returns the rectangle relative to the source for the given transformation matrix. + /// + /// The source rectangle. + /// The transformation matrix. + /// + /// The . + /// + public static Rectangle GetTransformedRectangle(Rectangle rectangle, Matrix3x2 matrix) + { + if (rectangle.Equals(default) || Matrix3x2.Identity.Equals(matrix)) + { + return rectangle; + } + + var tl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Top), matrix); + var tr = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Top), matrix); + var bl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Bottom), matrix); + var br = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix); + + return GetBoundingRectangle(tl, tr, bl, br); + } + + private static Rectangle GetBoundingRectangle(Vector2 tl, Vector2 tr, Vector2 bl, Vector2 br) + { + // Find the minimum and maximum "corners" based on the given vectors + float left = MathF.Min(tl.X, MathF.Min(tr.X, MathF.Min(bl.X, br.X))); + float top = MathF.Min(tl.Y, MathF.Min(tr.Y, MathF.Min(bl.Y, br.Y))); + float right = MathF.Max(tl.X, MathF.Max(tr.X, MathF.Max(bl.X, br.X))); + float bottom = MathF.Max(tl.Y, MathF.Max(tr.Y, MathF.Max(bl.Y, br.Y))); + + return Rectangle.Round(RectangleF.FromLTRB(left, top, right, bottom)); + } + } +} diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index 0ec1e295d9..3f24969a3d 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing /// The public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix, IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessor(matrix, sampler, source.GetCurrentSize())); + => source.ApplyProcessor(new AffineTransformProcessorOld(matrix, sampler, source.GetCurrentSize())); /// /// Transforms an image by the given matrix using the specified sampling algorithm @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing { var t = Matrix3x2.CreateTranslation(-rectangle.Location); Matrix3x2 combinedMatrix = t * matrix; - return source.ApplyProcessor(new AffineTransformProcessor(combinedMatrix, sampler, rectangle.Size)); + return source.ApplyProcessor(new AffineTransformProcessorOld(combinedMatrix, sampler, rectangle.Size)); } /// @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Processing IResampler sampler, Size destinationSize) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessor(matrix, sampler, destinationSize)); + => source.ApplyProcessor(new AffineTransformProcessorOld(matrix, sampler, destinationSize)); /// /// Transforms an image by the given matrix. From 0b8d9d1b081e847b34fdd8de71cf8f6a77fc5f46 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 6 Nov 2018 21:04:30 +0100 Subject: [PATCH 169/238] simplify calculations by using intermediate results instead of calculating the same stuff multiple times --- .../Converters/CieXyzToHunterLabConverter.cs | 8 +++++--- .../Converters/HunterLabToCieXyzConverter.cs | 9 ++++++--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 ++-- .../Quantization/FrameQuantizerBase{TPixel}.cs | 6 ++++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs index c27c61608d..f21235d06c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs @@ -45,9 +45,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float ka = ComputeKa(this.HunterLabWhitePoint); float kb = ComputeKb(this.HunterLabWhitePoint); - float l = 100 * MathF.Sqrt(y / yn); - float a = ka * (((x / xn) - (y / yn)) / MathF.Sqrt(y / yn)); - float b = kb * (((y / yn) - (z / zn)) / MathF.Sqrt(y / yn)); + float yByYn = y / yn; + float sqrtYbyYn = MathF.Sqrt(yByYn); + float l = 100 * sqrtYbyYn; + float a = ka * (((x / xn) - yByYn) / sqrtYbyYn); + float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn); if (float.IsNaN(a)) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs index 783d29a557..4d6808e6c0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs @@ -26,9 +26,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float ka = ComputeKa(input.WhitePoint); float kb = ComputeKb(input.WhitePoint); - float y = ImageMaths.Pow2(l / 100F) * yn; - float x = (((a / ka) * MathF.Sqrt(y / yn)) + (y / yn)) * xn; - float z = (((b / kb) * MathF.Sqrt(y / yn)) - (y / yn)) * (-zn); + float pow = ImageMaths.Pow2(l / 100F); + float sqrtPow = MathF.Sqrt(pow); + float y = pow * yn; + + float x = (((a / ka) * sqrtPow) + pow) * xn; + float z = (((b / kb) * sqrtPow) - pow) * (-zn); return new CieXyz(x, y, z); } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7ae716aa05..468f619b94 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -896,9 +896,9 @@ namespace SixLabors.ImageSharp.Formats.Png ref byte sourceRef = ref MemoryMarshal.GetReference(source); ref byte resultRef = ref MemoryMarshal.GetReference(result); - byte mask = (byte)(0xFF >> (8 - bits)); - byte shift0 = (byte)(8 - bits); int shift = 8 - bits; + byte mask = (byte)(0xFF >> shift); + byte shift0 = (byte)shift; int v = 0; int resultOffset = 0; diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index a8c6c5d7e0..3b9b046a00 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -139,8 +139,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization protected byte GetTransparentIndex() { // Transparent pixels are much more likely to be found at the end of a palette. - int index = this.paletteVector.Length - 1; - for (int i = this.paletteVector.Length - 1; i >= 0; i--) + int paletteVectorLengthMinus1 = this.paletteVector.Length - 1; + + int index = paletteVectorLengthMinus1; + for (int i = paletteVectorLengthMinus1; i >= 0; i--) { ref Vector4 candidate = ref this.paletteVector[i]; if (candidate.Equals(default)) From ea6fc641c394abe1dc57cf1217289b61919bbabe Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 14:01:41 +0100 Subject: [PATCH 170/238] inline division as it's only used in some cases (and done at most once) --- src/ImageSharp/Processing/ResizeHelper.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index b9233937b1..92af89d9e8 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -337,21 +337,19 @@ namespace SixLabors.ImageSharp.Processing float percentHeight = MathF.Abs(height / (float)sourceHeight); float percentWidth = MathF.Abs(width / (float)sourceWidth); - float sourceRatio = (float)sourceHeight / sourceWidth; - // Find the shortest distance to go. int widthDiff = sourceWidth - width; int heightDiff = sourceHeight - height; if (widthDiff < heightDiff) { - destinationHeight = (int)MathF.Round(width * sourceRatio); + destinationHeight = (int)MathF.Round(width * ((float)sourceHeight / sourceWidth)); height = destinationHeight; destinationWidth = width; } else if (widthDiff > heightDiff) { - destinationWidth = (int)MathF.Round(height / sourceRatio); + destinationWidth = (int)MathF.Round(height * ((float)sourceWidth / sourceHeight)); destinationHeight = height; width = destinationWidth; } From df155496b751e8132298eb9ff72f527a865f9337 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:02:50 +0100 Subject: [PATCH 171/238] inline variable --- .../Processing/Processors/Text/DrawTextProcessor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index 487c880644..266d842bfa 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -139,10 +139,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text fistRow = -startY; } - int end = operation.Map.Height; - int maxHeight = source.Height - startY; - end = Math.Min(end, maxHeight); + int end = Math.Min(operation.Map.Height, maxHeight); for (int row = fistRow; row < end; row++) { From 74dba7a9edf22b86d0f682e999af62b26faa6a11 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:04:42 +0100 Subject: [PATCH 172/238] unwrap for-loop to avoid conditional check inside it is known beforehand when the if condition inside the loop will not match: only in the last iteration. Thus we can loop once less and append the last element afterwards. --- src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 2be5addc2f..81393342d6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -543,15 +543,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components { var sb = new StringBuilder(); sb.Append('['); - for (int i = 0; i < Size; i++) + for (int i = 0; i < Size - 1; i++) { sb.Append(this[i]); - if (i < Size - 1) - { - sb.Append(','); - } + sb.Append(','); } + sb.Append(this[Size - 1]); + sb.Append(']'); return sb.ToString(); } From 3ebcebe99e8c1bce7f285a8c94c7b2001d00bbda Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:05:56 +0100 Subject: [PATCH 173/238] inline variable initialization --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 67f665576b..f6da9cb2ec 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -856,10 +856,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private void ProcessStartOfScanMarker() { int selectorsCount = this.InputStream.ReadByte(); - int componentIndex = -1; for (int i = 0; i < selectorsCount; i++) { - componentIndex = -1; + int componentIndex = -1; int selector = this.InputStream.ReadByte(); for (int j = 0; j < this.Frame.ComponentIds.Length; j++) From bb360ce3568f33da0f969d0f5708a84b58fd493c Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:48:19 +0100 Subject: [PATCH 174/238] invert condition: always assign literal 1, substract only on special case --- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index 34c353ec97..2d32fd23aa 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -309,10 +309,10 @@ namespace SixLabors.ImageSharp.Formats.Gif // Non-empty slot if (Unsafe.Add(ref hashTableRef, i) >= 0) { - int disp = hsizeReg - i; - if (i == 0) + int disp = 1; + if (i != 0) { - disp = 1; + disp = hsizeReg - i; } do From b6e9eb6f68b079a6f577a4ae550784453946aca2 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:56:38 +0100 Subject: [PATCH 175/238] multiply once and reuse --- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index a4677ba2b7..0dcbd8fef7 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -822,11 +822,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { for (int i = 0; i < componentCount; i++) { - this.buffer[(3 * i) + 6] = (byte)(i + 1); + int i3 = 3 * i; + this.buffer[i3 + 6] = (byte)(i + 1); // We use 4:2:0 chroma subsampling by default. - this.buffer[(3 * i) + 7] = subsamples[i]; - this.buffer[(3 * i) + 8] = chroma[i]; + this.buffer[i3 + 7] = subsamples[i]; + this.buffer[i3 + 8] = chroma[i]; } } From 34481a645a7d7d257a3e0f661ba25e49da4993b7 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 16:02:54 +0100 Subject: [PATCH 176/238] avoid local variable copy when the original is never changed --- src/ImageSharp/Formats/Png/PngScanlineProcessor.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 3fe590ee24..420775eca9 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -190,12 +190,11 @@ namespace SixLabors.ImageSharp.Formats.Png else { Rgba32 rgba32 = default; - int bps = bytesPerSample; for (int x = 0; x < header.Width; x++) { int offset = x * bytesPerPixel; byte luminance = Unsafe.Add(ref scanlineSpanRef, offset); - byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bps); + byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample); rgba32.R = luminance; rgba32.G = luminance; From 0da4c45cbd79059cc499522c4a76aa7294eb2b74 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 16:03:49 +0100 Subject: [PATCH 177/238] return first matching ImageFormat when iterating over FormatDetectors --- src/ImageSharp/Image.FromBytes.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 07adc03ff6..34927e6e2b 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -198,18 +198,17 @@ namespace SixLabors.ImageSharp return null; } - IImageFormat format = default; foreach (IImageFormatDetector detector in config.ImageFormatsManager.FormatDetectors) { IImageFormat f = detector.DetectFormat(data); if (f != null) { - format = f; + return f; } } - return format; + return default; } /// From e60deb73af13c47d1054f49cdc0cc9e7664c1351 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 23:33:22 +0100 Subject: [PATCH 178/238] avoid doubled increment in for loop and multiple array indexer access --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index eb519f4214..5a6cc1260e 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -310,9 +310,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp } else { - for (int i = 0; i < cmd[0]; i++) + int max = cmd[0] + count; + byte cmd1 = cmd[1]; + + for (; count < max; count++) { - buffer[count++] = cmd[1]; + buffer[count] = cmd1; } } } From 90e4a2ff0f9693c198ca6a314548b0923bf6a959 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 14:47:17 +0100 Subject: [PATCH 179/238] simplify BoxBlurProcessor kernel initialization old code seemed to be a relict from the GaussianBlurProcessor where this pattern made sense. Here each value of the matrix is just 1.0/size as a result, and we can leverage DenseMatrix.Fill() for that. --- .../Convolution/BoxBlurProcessor.cs | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index 0ec62ac3d4..38dc638b90 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -66,36 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution ? new DenseMatrix(size, 1) : new DenseMatrix(1, size); - float sum = 0F; - for (int i = 0; i < size; i++) - { - float x = 1; - sum += x; - if (horizontal) - { - kernel[0, i] = x; - } - else - { - kernel[i, 0] = x; - } - } - - // Normalize kernel so that the sum of all weights equals 1 - if (horizontal) - { - for (int i = 0; i < size; i++) - { - kernel[0, i] = kernel[0, i] / sum; - } - } - else - { - for (int i = 0; i < size; i++) - { - kernel[i, 0] = kernel[i, 0] / sum; - } - } + kernel.Fill(1.0F / size); return kernel; } From 2afd0d572970a1dbbf48e0707ddab23ae86ec648 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 7 Nov 2018 00:00:41 +0000 Subject: [PATCH 180/238] Cleanup TransformKernel and handle negative transform dimensions --- .../Transforms/AffineTransformProcessor.cs | 6 ++++++ .../Processors/Transforms/TransformKernelMap.cs | 15 ++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index edddab1811..f63baa95c6 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -38,6 +38,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // We want to resize the canvas here taking into account any translations. this.TargetDimensions = new Size(this.transformedRectangle.Right, this.transformedRectangle.Bottom); + + // Handle a negative translation that exceeds the original with of the image. + if (this.TargetDimensions.Width <= 0 || this.TargetDimensions.Height <= 0) + { + this.TargetDimensions = sourceSize; + } } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs index 5acc7213cb..531edbc45b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs @@ -21,8 +21,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { private readonly Buffer2D yBuffer; private readonly Buffer2D xBuffer; - private readonly float yScale; - private readonly float xScale; private readonly int yLength; private readonly int xLength; private readonly Vector2 extents; @@ -39,12 +37,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public TransformKernelMap(Configuration configuration, Size source, Size destination, IResampler sampler) { this.sampler = sampler; - (float radius, float scale) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - (float radius, float scale) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); + float yRadius = this.GetSamplingRadius(source.Height, destination.Height); + float xRadius = this.GetSamplingRadius(source.Width, destination.Width); - this.yScale = yRadiusScale.scale; - this.xScale = xRadiusScale.scale; - this.extents = new Vector2(xRadiusScale.radius, yRadiusScale.radius); + this.extents = new Vector2(xRadius, yRadius); this.xLength = (int)MathF.Ceiling((this.extents.X * 2) + 2); this.yLength = (int)MathF.Ceiling((this.extents.Y * 2) + 2); @@ -167,7 +163,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // } } - private (float radius, float scale) GetSamplingRadius(int sourceSize, int destinationSize) + [MethodImpl(InliningOptions.ShortMethod)] + private float GetSamplingRadius(int sourceSize, int destinationSize) { float scale = (float)sourceSize / destinationSize; @@ -176,7 +173,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms scale = 1F; } - return (MathF.Ceiling(scale * this.sampler.Radius), scale); + return MathF.Ceiling(scale * this.sampler.Radius); } public void Dispose() From 321cca6e815ff0abb73d3a7b2168bfa9a670fdf3 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 7 Nov 2018 18:47:08 +0100 Subject: [PATCH 181/238] #771: change order of addition as proposed by @dlemstra added comments as explanation --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 5a6cc1260e..ef3ca24ee8 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -310,8 +310,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp } else { - int max = cmd[0] + count; - byte cmd1 = cmd[1]; + int max = count + cmd[0]; // as we start at the current count in the following loop, max is count + cmd[0] + byte cmd1 = cmd[1]; // store the value to avoid the repeated indexer access inside the loop for (; count < max; count++) { From 8205216dfc07f4ea6ebafcbbbbc391c8426173e7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 10 Nov 2018 14:20:52 +0000 Subject: [PATCH 182/238] Introduce AffineTransformBuilder --- .../Processing/AffineTransformBuilder.cs | 177 +++++++++++++ .../Transforms/AffineTransformProcessor.cs | 33 ++- .../Transforms/AffineTransformProcessorOld.cs | 239 ------------------ .../CenteredAffineTransformProcessor.cs | 38 --- .../Processors/Transforms/RotateProcessor.cs | 2 +- .../Processors/Transforms/SkewProcessor.cs | 8 +- .../Processors/Transforms/TransformHelpers.cs | 20 -- .../Transforms/TransformKernelMap.cs | 56 ++-- .../Processors/Transforms/TransformUtils.cs | 78 ++++-- .../Processing/TransformExtensions.cs | 54 +--- .../ImageSharp.Benchmarks/Samplers/Rotate.cs | 10 +- tests/ImageSharp.Benchmarks/Samplers/Skew.cs | 45 ++++ .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 22 +- .../Transforms/AffineTransformTests.cs | 54 ++-- 14 files changed, 360 insertions(+), 476 deletions(-) create mode 100644 src/ImageSharp/Processing/AffineTransformBuilder.cs delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs create mode 100644 tests/ImageSharp.Benchmarks/Samplers/Skew.cs diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs new file mode 100644 index 0000000000..e5ce1450f7 --- /dev/null +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -0,0 +1,177 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using System.Numerics; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// A helper class for constructing instances for use in affine transforms. + /// + public class AffineTransformBuilder + { + private readonly List matrices = new List(); + private Rectangle rectangle; + + /// + /// Initializes a new instance of the class. + /// + /// The source image size. + public AffineTransformBuilder(Size sourceSize) => this.Size = sourceSize; + + /// + /// Initializes a new instance of the class. + /// + /// The source rectangle. + public AffineTransformBuilder(Rectangle sourceRectangle) + : this(sourceRectangle.Size) + => this.rectangle = sourceRectangle; + + /// + /// Prepends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) + { + this.matrices.Insert(0, TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + return this; + } + + /// + /// Gets the source image size. + /// + internal Size Size { get; } + + /// + /// Appends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) + { + this.matrices.Add(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + return this; + } + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder PrependScaleMatrix(SizeF scales) + { + this.matrices.Insert(0, Matrix3x2Extensions.CreateScale(scales)); + return this; + } + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder AppendScaleMatrix(SizeF scales) + { + this.matrices.Add(Matrix3x2Extensions.CreateScale(scales)); + return this; + } + + /// + /// Prepends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + public AffineTransformBuilder PrependSkewMatrixDegrees(float degreesX, float degreesY) + { + this.matrices.Insert(0, TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + return this; + } + + /// + /// Appends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + public AffineTransformBuilder AppendSkewMatrixDegrees(float degreesX, float degreesY) + { + this.matrices.Add(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + return this; + } + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder PrependTranslationMatrix(PointF position) + { + this.matrices.Insert(0, Matrix3x2Extensions.CreateTranslation(position)); + return this; + } + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder AppendTranslationMatrix(PointF position) + { + this.matrices.Add(Matrix3x2Extensions.CreateTranslation(position)); + return this; + } + + /// + /// Prepends a raw matrix. + /// + /// The matrix to prepend. + /// The . + public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) + { + this.matrices.Insert(0, matrix); + return this; + } + + /// + /// Appends a raw matrix. + /// + /// The matrix to append. + /// The . + public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) + { + this.matrices.Add(matrix); + return this; + } + + /// + /// Returns the combined matrix. + /// + /// The . + public Matrix3x2 BuildMatrix() + { + Matrix3x2 matrix = Matrix3x2.Identity; + + // Translate the origin matrix to cater for source rectangle offsets. + if (!this.rectangle.Equals(default)) + { + matrix *= Matrix3x2.CreateTranslation(-this.rectangle.Location); + } + + foreach (Matrix3x2 m in this.matrices) + { + matrix *= m; + } + + return matrix; + } + + /// + /// Removes all matrices from the builder. + /// + public void Clear() => this.matrices.Clear(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index f63baa95c6..fb42b83341 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -19,8 +19,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal class AffineTransformProcessor : TransformProcessorBase where TPixel : struct, IPixel { - private readonly Rectangle transformedRectangle; - /// /// Initializes a new instance of the class. /// @@ -32,18 +30,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Guard.NotNull(sampler, nameof(sampler)); this.Sampler = sampler; this.TransformMatrix = matrix; - this.transformedRectangle = TransformUtils.GetTransformedRectangle( - new Rectangle(Point.Empty, sourceSize), - matrix); - - // We want to resize the canvas here taking into account any translations. - this.TargetDimensions = new Size(this.transformedRectangle.Right, this.transformedRectangle.Bottom); - - // Handle a negative translation that exceeds the original with of the image. - if (this.TargetDimensions.Width <= 0 || this.TargetDimensions.Height <= 0) - { - this.TargetDimensions = sourceSize; - } + this.TargetDimensions = TransformUtils.GetTransformedSize(sourceSize, matrix); } /// @@ -79,10 +66,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Rectangle sourceRectangle, Configuration configuration) { + // Handle tranforms that result in output identical to the original. + if (this.TransformMatrix.Equals(Matrix3x2.Identity)) + { + // The cloned will be blank here copy all the pixel data over + source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); + return; + } + int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; - Rectangle sourceBounds = source.Bounds(); var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. @@ -102,7 +96,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = 0; x < width; x++) { var point = Point.Transform(new Point(x, y), matrix); - if (sourceBounds.Contains(point.X, point.Y)) + if (sourceRectangle.Contains(point.X, point.Y)) { destRow[x] = source[point.X, point.Y]; } @@ -113,7 +107,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - using (var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler)) + var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler); + try { ParallelHelper.IterateRowsWithTempBuffer( targetBounds, @@ -140,6 +135,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } }); } + finally + { + kernel.Dispose(); + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs deleted file mode 100644 index 5891afd9a6..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessorOld.cs +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.ParallelUtils; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// Provides the base methods to perform affine transforms on an image. - /// - /// The pixel format. - internal class AffineTransformProcessorOld : InterpolatedTransformProcessorBase - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The transform matrix - /// The sampler to perform the transform operation. - /// The target dimensions to constrain the transformed image to. - public AffineTransformProcessorOld(Matrix3x2 matrix, IResampler sampler, Size targetDimensions) - : base(sampler) - { - this.TransformMatrix = matrix; - this.TargetDimensions = targetDimensions; - } - - /// - /// Gets the matrix used to supply the affine transform - /// - public Matrix3x2 TransformMatrix { get; } - - /// - /// Gets the target dimensions to constrain the transformed image to - /// - public Size TargetDimensions { get; } - - /// - protected override Image CreateDestination(Image source, Rectangle sourceRectangle) - { - // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); - - // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); - } - - /// - protected override void OnFrameApply( - ImageFrame source, - ImageFrame destination, - Rectangle sourceRectangle, - Configuration configuration) - { - int height = this.TargetDimensions.Height; - int width = this.TargetDimensions.Width; - - Rectangle sourceBounds = source.Bounds(); - var targetBounds = new Rectangle(0, 0, width, height); - - // Since could potentially be resizing the canvas we might need to re-calculate the matrix - Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); - - // Convert from screen to world space. - Matrix3x2.Invert(matrix, out matrix); - - if (this.Sampler is NearestNeighborResampler) - { - ParallelHelper.IterateRows( - targetBounds, - configuration, - rows => - { - for (int y = rows.Min; y < rows.Max; y++) - { - Span destRow = destination.GetPixelRowSpan(y); - - for (int x = 0; x < width; x++) - { - var point = Point.Transform(new Point(x, y), matrix); - if (sourceBounds.Contains(point.X, point.Y)) - { - destRow[x] = source[point.X, point.Y]; - } - } - } - }); - - return; - } - - int maxSourceX = source.Width - 1; - int maxSourceY = source.Height - 1; - (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); - (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - float xScale = xRadiusScale.scale; - float yScale = yRadiusScale.scale; - var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); - IResampler sampler = this.Sampler; - var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); - int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); - int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); - - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) - using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) - { - ParallelHelper.IterateRows( - targetBounds, - configuration, - rows => - { - for (int y = rows.Min; y < rows.Max; y++) - { - ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); - ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); - - for (int x = 0; x < width; x++) - { - // Use the single precision position to calculate correct bounding pixels - // otherwise we get rogue pixels outside of the bounds. - var point = Vector2.Transform(new Vector2(x, y), matrix); - - // Clamp sampling pixel radial extents to the source image edges - Vector2 maxXY = point + radius; - Vector2 minXY = point - radius; - - // max, maxY, minX, minY - var extents = new Vector4( - MathF.Floor(maxXY.X + .5F), - MathF.Floor(maxXY.Y + .5F), - MathF.Ceiling(minXY.X - .5F), - MathF.Ceiling(minXY.Y - .5F)); - - int right = (int)extents.X; - int bottom = (int)extents.Y; - int left = (int)extents.Z; - int top = (int)extents.W; - - extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); - - int maxX = (int)extents.X; - int maxY = (int)extents.Y; - int minX = (int)extents.Z; - int minY = (int)extents.W; - - if (minX == maxX || minY == maxY) - { - continue; - } - - // It appears these have to be calculated on-the-fly. - // Precalculating transformed weights would require prior knowledge of every transformed pixel location - // since they can be at sub-pixel positions on both axis. - // I've optimized where I can but am always open to suggestions. - if (yScale > 1 && xScale > 1) - { - CalculateWeightsDown( - top, - bottom, - minY, - maxY, - point.Y, - sampler, - yScale, - ref ySpanRef, - yLength); - - CalculateWeightsDown( - left, - right, - minX, - maxX, - point.X, - sampler, - xScale, - ref xSpanRef, - xLength); - } - else - { - CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); - CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); - } - - // Now multiply the results against the offsets - Vector4 sum = Vector4.Zero; - for (int yy = 0, j = minY; j <= maxY; j++, yy++) - { - float yWeight = Unsafe.Add(ref ySpanRef, yy); - - for (int xx = 0, i = minX; i <= maxX; i++, xx++) - { - float xWeight = Unsafe.Add(ref xSpanRef, xx); - - // Values are first premultiplied to prevent darkening of edge pixels - var current = source[i, j].ToVector4(); - Vector4Utils.Premultiply(ref current); - sum += current * xWeight * yWeight; - } - } - - ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); - - // Reverse the premultiplication - Vector4Utils.UnPremultiply(ref sum); - dest.FromVector4(sum); - } - } - }); - } - } - - /// - /// Gets a transform matrix adjusted for final processing based upon the target image bounds. - /// - /// The source image bounds. - /// The destination image bounds. - /// - /// The . - /// - protected virtual Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - => this.TransformMatrix; - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs deleted file mode 100644 index 82614dc8c2..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// A base class that provides methods to allow the automatic centering of affine transforms - /// - /// The pixel format. - internal abstract class CenteredAffineTransformProcessor : AffineTransformProcessorOld - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The transform matrix - /// The sampler to perform the transform operation. - /// The source image size - protected CenteredAffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize) - : base(matrix, sampler, GetTransformedDimensions(sourceSize, matrix)) - { - } - - /// - protected override Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - => TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix); - - private static Size GetTransformedDimensions(Size sourceDimensions, Matrix3x2 matrix) - { - var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height); - return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix).Size; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index cbf82cc9b0..57cca4bf9e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The source image size public RotateProcessor(float degrees, IResampler sampler, Size sourceSize) : base( - TransformUtils.CreateCenteredRotationMatrixDegrees(degrees, sourceSize), + TransformUtils.CreateRotationMatrixDegrees(degrees, sourceSize), sampler, sourceSize) => this.Degrees = degrees; diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs index a0cfa63794..4a006a9dfe 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -11,7 +10,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides methods that allow the skewing of images. /// /// The pixel format. - internal class SkewProcessor : CenteredAffineTransformProcessor + internal class SkewProcessor : AffineTransformProcessor where TPixel : struct, IPixel { /// @@ -33,7 +32,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the skew operation. /// The source image size public SkewProcessor(float degreesX, float degreesY, IResampler sampler, Size sourceSize) - : base(Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty), sampler, sourceSize) + : base( + TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, sourceSize), + sampler, + sourceSize) { this.DegreesX = degreesX; this.DegreesY = degreesY; diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs index b22fa64cfd..2e85f6c2cc 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs @@ -102,26 +102,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return centered; } - /// - /// Returns the bounding rectangle relative to the source for the given transformation matrix. - /// - /// The source rectangle. - /// The transformation matrix. - /// - /// The . - /// - public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) - { - // Calculate the position of the four corners in world space by applying - // The world matrix to the four corners in object space (0, 0, width, height) - var tl = Vector2.Transform(Vector2.Zero, matrix); - var tr = Vector2.Transform(new Vector2(rectangle.Width, 0), matrix); - var bl = Vector2.Transform(new Vector2(0, rectangle.Height), matrix); - var br = Vector2.Transform(new Vector2(rectangle.Width, rectangle.Height), matrix); - - return GetBoundingRectangle(tl, tr, bl, br); - } - /// /// Returns the bounding rectangle relative to the source for the given transformation matrix. /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs index 531edbc45b..573120888f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs @@ -9,20 +9,15 @@ using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; -// TODO: It would be great if we could somehow optimize this to calculate the weights once. -// currently we cannot do that as we are calulating the weight of the transformed point dimension -// not the point in the original image. namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Contains the methods required to calculate kernel sampling weights on-the-fly. + /// Contains the methods required to calculate transform kernel convolution. /// internal class TransformKernelMap : IDisposable { private readonly Buffer2D yBuffer; private readonly Buffer2D xBuffer; - private readonly int yLength; - private readonly int xLength; private readonly Vector2 extents; private Vector4 maxSourceExtents; private readonly IResampler sampler; @@ -41,12 +36,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float xRadius = this.GetSamplingRadius(source.Width, destination.Width); this.extents = new Vector2(xRadius, yRadius); - this.xLength = (int)MathF.Ceiling((this.extents.X * 2) + 2); - this.yLength = (int)MathF.Ceiling((this.extents.Y * 2) + 2); + int xLength = (int)MathF.Ceiling((this.extents.X * 2) + 2); + int yLength = (int)MathF.Ceiling((this.extents.Y * 2) + 2); - // We use 2D buffers so that we can access the weight spans in parallel. - this.yBuffer = configuration.MemoryAllocator.Allocate2D(this.yLength, destination.Height); - this.xBuffer = configuration.MemoryAllocator.Allocate2D(this.xLength, destination.Height); + // We use 2D buffers so that we can access the weight spans per row in parallel. + this.yBuffer = configuration.MemoryAllocator.Allocate2D(yLength, destination.Height); + this.xBuffer = configuration.MemoryAllocator.Allocate2D(xLength, destination.Height); int maxX = source.Width - 1; int maxY = source.Height - 1; @@ -82,42 +77,34 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Vector2 minXY = transformedPoint - this.extents; Vector2 maxXY = transformedPoint + this.extents; - // minX, minY, maxX, maxY + // left, top, right, bottom var extents = new Vector4( MathF.Ceiling(minXY.X - .5F), MathF.Ceiling(minXY.Y - .5F), MathF.Floor(maxXY.X + .5F), MathF.Floor(maxXY.Y + .5F)); + extents = Vector4.Clamp(extents, Vector4.Zero, this.maxSourceExtents); + int left = (int)extents.X; int top = (int)extents.Y; int right = (int)extents.Z; int bottom = (int)extents.W; - extents = Vector4.Clamp(extents, Vector4.Zero, this.maxSourceExtents); - - int minX = (int)extents.X; - int minY = (int)extents.Y; - int maxX = (int)extents.Z; - int maxY = (int)extents.W; - - if (minX == maxX || minY == maxY) + if (left == right || top == bottom) { return; } - // TODO: Get Anton to use his superior brain on this one. - // It looks to me like we're calculating the same weights over and over again - // since min(X+Y) and max(X+Y) are the same distance apart. - this.CalculateWeights(minY, maxY, maxY - minY, transformedPoint.Y, ref ySpanRef); - this.CalculateWeights(minX, maxX, maxX - minX, transformedPoint.X, ref xSpanRef); + this.CalculateWeights(top, bottom, transformedPoint.Y, ref ySpanRef); + this.CalculateWeights(left, right, transformedPoint.X, ref xSpanRef); Vector4 sum = Vector4.Zero; - for (int kernelY = 0, y = minY; y <= maxY; y++, kernelY++) + for (int kernelY = 0, y = top; y <= bottom; y++, kernelY++) { float yWeight = Unsafe.Add(ref ySpanRef, kernelY); - for (int kernelX = 0, x = minX; x <= maxX; x++, kernelX++) + for (int kernelX = 0, x = left; x <= right; x++, kernelX++) { float xWeight = Unsafe.Add(ref xSpanRef, kernelX); @@ -138,29 +125,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The minimum sampling offset /// The maximum sampling offset - /// The length of the weights collection /// The transformed point dimension /// The reference to the collection of weights [MethodImpl(InliningOptions.ShortMethod)] - private void CalculateWeights(int min, int max, int length, float point, ref float weightsRef) + private void CalculateWeights(int min, int max, float point, ref float weightsRef) { float sum = 0; for (int x = 0, i = min; i <= max; i++, x++) { float weight = this.sampler.GetValue(i - point); sum += weight; - Unsafe.Add(ref weightsRef, x) = this.sampler.GetValue(i - point); + Unsafe.Add(ref weightsRef, x) = weight; } - - // TODO: Do we need this? Check what happens when we scale an image down. - // if (sum > 0) - // { - // for (int i = 0; i < length; i++) - // { - // ref float wRef = ref Unsafe.Add(ref weightsRef, i); - // wRef /= sum; - // } - // } } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs index 7d03502499..10cf49c34b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Contains utility methods for working with transforms. /// - public static class TransformUtils + internal static class TransformUtils { /// /// Creates a centered rotation matrix using the given rotation in degrees and the source size. @@ -18,43 +18,33 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The amount of rotation, in degrees. /// The source image size. /// The . - public static Matrix3x2 CreateCenteredRotationMatrixDegrees(float degrees, Size size) + public static Matrix3x2 CreateRotationMatrixDegrees(float degrees, Size size) => CreateCenteredTransformMatrix( new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty)); /// - /// Gets the centered transform matrix based upon the source and destination rectangles. + /// Creates a centered skew matrix from the give angles in degrees and the source size. /// - /// The source image bounds. - /// The transformation matrix. - /// The - public static Matrix3x2 CreateCenteredTransformMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) - { - Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); - - // We invert the matrix to handle the transformation from screen to world space. - // This ensures scaling matrices are correct. - Matrix3x2.Invert(matrix, out Matrix3x2 inverted); - - var translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); - var translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); - - // Translate back to world space. - Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); - - return centered; - } + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The source image size. + /// The . + public static Matrix3x2 CreateSkewMatrixDegrees(float degreesX, float degreesY, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty)); /// /// Gets the centered transform matrix based upon the source and destination rectangles. /// /// The source image bounds. - /// The destination image bounds. /// The transformation matrix. /// The - public static Matrix3x2 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix3x2 matrix) + public static Matrix3x2 CreateCenteredTransformMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) { + Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); + // We invert the matrix to handle the transformation from screen to world space. // This ensures scaling matrices are correct. Matrix3x2.Invert(matrix, out Matrix3x2 inverted); @@ -79,8 +69,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) { Rectangle transformed = GetTransformedRectangle(rectangle, matrix); - - // TODO: Check this. return new Rectangle(0, 0, transformed.Width, transformed.Height); } @@ -107,6 +95,44 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return GetBoundingRectangle(tl, tr, bl, br); } + /// + /// Returns the size relative to the source for the given transformation matrix. + /// + /// The source size. + /// The transformation matrix. + /// + /// The . + /// + public static Size GetTransformedSize(Size size, Matrix3x2 matrix) + { + Guard.IsTrue(size.Width > 0 && size.Height > 0, nameof(size), "Source size dimensions cannot be 0!"); + + if (matrix.Equals(default) || matrix.Equals(Matrix3x2.Identity)) + { + return size; + } + + Rectangle rectangle = GetTransformedRectangle(new Rectangle(Point.Empty, size), matrix); + + // We want to resize the canvas here taking into account any translations. + int height = rectangle.Top < 0 ? rectangle.Bottom : Math.Max(rectangle.Height, rectangle.Bottom); + int width = rectangle.Left < 0 ? rectangle.Right : Math.Max(rectangle.Width, rectangle.Right); + + // If location in either direction is translated to a negative value equal to or exceeding the + // dimensions in eith direction we need to reassign the dimension. + if (height <= 0) + { + height = rectangle.Height; + } + + if (width <= 0) + { + width = rectangle.Width; + } + + return new Size(width, height); + } + private static Rectangle GetBoundingRectangle(Vector2 tl, Vector2 tr, Vector2 bl, Vector2 br) { // Find the minimum and maximum "corners" based on the given vectors diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index 3f24969a3d..4cbd1b041f 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -18,65 +18,23 @@ namespace SixLabors.ImageSharp.Processing /// /// The pixel format. /// The image to transform. - /// The transformation matrix. + /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix) + public static IImageProcessingContext Transform(this IImageProcessingContext source, AffineTransformBuilder builder) where TPixel : struct, IPixel - => Transform(source, matrix, KnownResamplers.Bicubic); + => Transform(source, builder, KnownResamplers.Bicubic); /// /// Transforms an image by the given matrix using the specified sampling algorithm. /// /// The pixel format. /// The image to transform. - /// The transformation matrix. - /// The to perform the resampling. - /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix, IResampler sampler) - where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessorOld(matrix, sampler, source.GetCurrentSize())); - - /// - /// Transforms an image by the given matrix using the specified sampling algorithm - /// and a rectangle defining the transform origin in the source image and the size of the result image. - /// - /// The pixel format. - /// The image to transform. - /// The transformation matrix. - /// The to perform the resampling. - /// - /// The rectangle defining the transform origin in the source image, and the size of the result image. - /// - /// The - public static IImageProcessingContext Transform( - this IImageProcessingContext source, - Matrix3x2 matrix, - IResampler sampler, - Rectangle rectangle) - where TPixel : struct, IPixel - { - var t = Matrix3x2.CreateTranslation(-rectangle.Location); - Matrix3x2 combinedMatrix = t * matrix; - return source.ApplyProcessor(new AffineTransformProcessorOld(combinedMatrix, sampler, rectangle.Size)); - } - - /// - /// Transforms an image by the given matrix using the specified sampling algorithm, - /// cropping or extending the image according to . - /// - /// The pixel format. - /// The image to transform. - /// The transformation matrix. + /// The affine transform builder. /// The to perform the resampling. - /// The size of the destination image. /// The - public static IImageProcessingContext Transform( - this IImageProcessingContext source, - Matrix3x2 matrix, - IResampler sampler, - Size destinationSize) + public static IImageProcessingContext Transform(this IImageProcessingContext source, AffineTransformBuilder builder, IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessorOld(matrix, sampler, destinationSize)); + => source.ApplyProcessor(new AffineTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); /// /// Transforms an image by the given matrix. diff --git a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs index c1456f9d77..f898576af0 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Samplers } } -// Nov 4 2018 +// Nov 7 2018 //BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17763 //Intel Core i7-6600U CPU 2.60GHz(Skylake), 1 CPU, 4 logical and 2 physical cores //.NET Core SDK = 2.1.403 @@ -36,4 +36,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Samplers // Method | Runtime | Mean | Error | StdDev | Allocated | //--------- |-------- |---------:|----------:|----------:|----------:| // DoRotate | Clr | 85.19 ms | 13.379 ms | 0.7560 ms | 6 KB | -// DoRotate | Core | 53.51 ms | 9.512 ms | 0.5375 ms | 4.29 KB | \ No newline at end of file +// DoRotate | Core | 53.51 ms | 9.512 ms | 0.5375 ms | 4.29 KB | + +// #### AFTER ####: +//Method | Runtime | Mean | Error | StdDev | Allocated | +//--------- |-------- |---------:|---------:|---------:|----------:| +// DoRotate | Clr | 77.08 ms | 23.97 ms | 1.354 ms | 6 KB | +// DoRotate | Core | 40.36 ms | 47.43 ms | 2.680 ms | 4.36 KB | \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Samplers/Skew.cs b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs new file mode 100644 index 0000000000..84819750af --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs @@ -0,0 +1,45 @@ +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Benchmarks.Samplers +{ + [Config(typeof(Config.ShortClr))] + public class Skew + { + [Benchmark] + public Size DoSkew() + { + using (var image = new Image(Configuration.Default, 400, 400, Rgba32.BlanchedAlmond)) + { + image.Mutate(x => x.Skew(20, 10)); + + return image.Size(); + } + } + } +} + +// Nov 7 2018 +//BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17763 +//Intel Core i7-6600U CPU 2.60GHz(Skylake), 1 CPU, 4 logical and 2 physical cores +//.NET Core SDK = 2.1.403 + +// [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT +// Job-KKDIMW : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 +// Job-IUZRFA : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + +//LaunchCount=1 TargetCount=3 WarmupCount=3 + +// #### BEFORE ####: +//Method | Runtime | Mean | Error | StdDev | Allocated | +//------- |-------- |---------:|---------:|----------:|----------:| +// DoSkew | Clr | 78.14 ms | 8.383 ms | 0.4736 ms | 6 KB | +// DoSkew | Core | 44.22 ms | 4.109 ms | 0.2322 ms | 4.28 KB | + +// #### AFTER ####: +//Method | Runtime | Mean | Error | StdDev | Allocated | +//------- |-------- |---------:|----------:|----------:|----------:| +// DoSkew | Clr | 71.63 ms | 25.589 ms | 1.4458 ms | 6 KB | +// DoSkew | Core | 38.99 ms | 8.640 ms | 0.4882 ms | 4.36 KB | \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 496692d969..564318e5e3 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -2,10 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; using Xunit; @@ -75,21 +73,15 @@ namespace SixLabors.ImageSharp.Tests using (Image image = provider.GetImage()) using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { - Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(45F); - Matrix3x2 scale = Matrix3x2Extensions.CreateScale(new SizeF(.25F, .25F)); - Matrix3x2 matrix = rotate * scale; + AffineTransformBuilder builder = new AffineTransformBuilder(blend.Size()) + .AppendRotateMatrixDegrees(45F) + .AppendScaleMatrix(new SizeF(.25F, .25F)) + .AppendTranslationMatrix(new PointF(10, 10)); - // Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor - Rectangle srcBounds = blend.Bounds(); - Rectangle destBounds = TransformHelpers.GetTransformedBoundingRectangle(srcBounds, matrix); - Matrix3x2 centeredMatrix = TransformHelpers.GetCenteredTransformMatrix(srcBounds, destBounds, matrix); - - // We pass a new rectangle here based on the dest bounds since we've offset the matrix - blend.Mutate(x => x.Transform( - centeredMatrix, - KnownResamplers.Bicubic, - new Rectangle(0, 0, destBounds.Width, destBounds.Height))); + // Apply a background color so we can see the translation. + blend.Mutate(x => x.Transform(builder).BackgroundColor(NamedColors.HotPink)); + // Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2); image.Mutate(x => x.DrawImage(blend, position, mode, .75F)); image.DebugSave(provider, new[] { "Transformed" }); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index ae572498a4..32280d48cd 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -78,15 +78,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler resampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - var rotate = Matrix3x2.CreateRotation((float)Math.PI / 4F, new Vector2(5 / 2F, 5 / 2F)); - var translate = Matrix3x2.CreateTranslation((7 - 5) / 2F, (7 - 5) / 2F); + AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + .AppendRotateMatrixDegrees((float)Math.PI / 4F); - Rectangle sourceRectangle = image.Bounds(); - Matrix3x2 matrix = rotate * translate; - - Rectangle destRectangle = TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix); - - image.Mutate(c => c.Transform(matrix, resampler, destRectangle)); + image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); VerifyAllPixelsAreWhiteOrTransparent(image); @@ -104,14 +99,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(angleDeg); - var translate = Matrix3x2.CreateTranslation(tx, ty); - var scale = Matrix3x2.CreateScale(sx, sy); - Matrix3x2 m = rotate * scale * translate; + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + .AppendRotateMatrixDegrees(angleDeg) + .AppendScaleMatrix(new SizeF(sx, sy)) + .AppendTranslationMatrix(new PointF(tx, ty)); - this.PrintMatrix(m); + this.PrintMatrix(builder.BuildMatrix()); - image.Mutate(i => i.Transform(m, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); FormattableString testOutputDetails = $"R({angleDeg})_S({sx},{sy})_T({tx},{ty})"; image.DebugSave(provider, testOutputDetails); @@ -126,9 +122,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - Matrix3x2 m = this.MakeManuallyCenteredMatrix(angleDeg, s, image); + AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + .AppendRotateMatrixDegrees(angleDeg) + .AppendScaleMatrix(new SizeF(s, s)); - image.Mutate(i => i.Transform(m, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); FormattableString testOutputDetails = $"R({angleDeg})_S({s})"; image.DebugSave(provider, testOutputDetails); @@ -155,13 +153,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void Transform_FromSourceRectangle1(TestImageProvider provider) where TPixel : struct, IPixel { - var rectangle = new Rectangle(48, 0, 96, 36); + var rectangle = new Rectangle(48, 0, 48, 24); using (Image image = provider.GetImage()) { - var m = Matrix3x2.CreateScale(2.0F, 1.5F); + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) + .AppendScaleMatrix(new SizeF(2, 1.5F)); - image.Mutate(i => i.Transform(m, KnownResamplers.Spline, rectangle)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -173,13 +173,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void Transform_FromSourceRectangle2(TestImageProvider provider) where TPixel : struct, IPixel { - var rectangle = new Rectangle(0, 24, 48, 48); + var rectangle = new Rectangle(0, 24, 48, 24); using (Image image = provider.GetImage()) { - var m = Matrix3x2.CreateScale(1.0F, 2.0F); + AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) + .AppendScaleMatrix(new SizeF(1F, 2F)); - image.Mutate(i => i.Transform(m, KnownResamplers.Spline, rectangle)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -194,12 +195,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - Matrix3x2 m = this.MakeManuallyCenteredMatrix(50, 0.6f, image); + AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + .AppendRotateMatrixDegrees(50) + .AppendScaleMatrix(new SizeF(.6F, .6F)); - image.Mutate(i => - { - i.Transform(m, sampler); - }); + image.Mutate(i => i.Transform(builder, sampler)); image.DebugSave(provider, resamplerName); image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); From 0daa647b69e1a995429bb575b54dcd8dc8a19440 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 14:38:33 +0100 Subject: [PATCH 183/238] fix typo in KirschKernels class name --- .../{KirshKernels.cs => KirschKernels.cs} | 4 ++-- .../Processors/Convolution/KirschProcessor.cs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) rename src/ImageSharp/Processing/Processors/Convolution/{KirshKernels.cs => KirschKernels.cs} (96%) diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs similarity index 96% rename from src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs rename to src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs index d315875089..86232e306a 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs @@ -6,9 +6,9 @@ using SixLabors.ImageSharp.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// - /// Contains the eight matrices used for Kirsh edge detection + /// Contains the eight matrices used for Kirsch edge detection /// - internal static class KirshKernels + internal static class KirschKernels { /// /// Gets the North gradient operator diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs index 46cf00c226..c3188676f3 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs @@ -23,27 +23,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override DenseMatrix North => KirshKernels.KirschNorth; + public override DenseMatrix North => KirschKernels.KirschNorth; /// - public override DenseMatrix NorthWest => KirshKernels.KirschNorthWest; + public override DenseMatrix NorthWest => KirschKernels.KirschNorthWest; /// - public override DenseMatrix West => KirshKernels.KirschWest; + public override DenseMatrix West => KirschKernels.KirschWest; /// - public override DenseMatrix SouthWest => KirshKernels.KirschSouthWest; + public override DenseMatrix SouthWest => KirschKernels.KirschSouthWest; /// - public override DenseMatrix South => KirshKernels.KirschSouth; + public override DenseMatrix South => KirschKernels.KirschSouth; /// - public override DenseMatrix SouthEast => KirshKernels.KirschSouthEast; + public override DenseMatrix SouthEast => KirschKernels.KirschSouthEast; /// - public override DenseMatrix East => KirshKernels.KirschEast; + public override DenseMatrix East => KirschKernels.KirschEast; /// - public override DenseMatrix NorthEast => KirshKernels.KirschNorthEast; + public override DenseMatrix NorthEast => KirschKernels.KirschNorthEast; } } \ No newline at end of file From b196a0897546115a583b129ca99e845a0e8c2265 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 4 Nov 2018 15:13:24 +0100 Subject: [PATCH 184/238] fix typo in local variable name --- .../Profiles/ICC/DataReader/IccDataReader.Curves.cs | 8 ++++---- .../ICC/DataReader/IccDataReader.TagDataEntry.cs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs index ee91ad7a18..b27083dc49 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs @@ -41,10 +41,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc public IccResponseCurve ReadResponseCurve(int channelCount) { var type = (IccCurveMeasurementEncodings)this.ReadUInt32(); - uint[] measurment = new uint[channelCount]; + uint[] measurement = new uint[channelCount]; for (int i = 0; i < channelCount; i++) { - measurment[i] = this.ReadUInt32(); + measurement[i] = this.ReadUInt32(); } Vector3[] xyzValues = new Vector3[channelCount]; @@ -56,8 +56,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc IccResponseNumber[][] response = new IccResponseNumber[channelCount][]; for (int i = 0; i < channelCount; i++) { - response[i] = new IccResponseNumber[measurment[i]]; - for (uint j = 0; j < measurment[i]; j++) + response[i] = new IccResponseNumber[measurement[i]]; + for (uint j = 0; j < measurement[i]; j++) { response[i][j] = this.ReadResponseNumber(); } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs index e41d9b3b8c..c572b7f210 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs @@ -628,16 +628,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc { int start = this.currentIndex - 8; // 8 is the tag header size ushort channelCount = this.ReadUInt16(); - ushort measurmentCount = this.ReadUInt16(); + ushort measurementCount = this.ReadUInt16(); - uint[] offset = new uint[measurmentCount]; - for (int i = 0; i < measurmentCount; i++) + uint[] offset = new uint[measurementCount]; + for (int i = 0; i < measurementCount; i++) { offset[i] = this.ReadUInt32(); } - var curves = new IccResponseCurve[measurmentCount]; - for (int i = 0; i < measurmentCount; i++) + var curves = new IccResponseCurve[measurementCount]; + for (int i = 0; i < measurementCount; i++) { this.currentIndex = (int)(start + offset[i]); curves[i] = this.ReadResponseCurve(channelCount); From 5589bd3e39007710b40d4f380690003a81209485 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 10 Nov 2018 21:14:30 +0000 Subject: [PATCH 185/238] Introduce ProjectiveTransformBuilder --- .../Processing/AffineTransformBuilder.cs | 10 +- .../Transforms/AffineTransformProcessor.cs | 6 +- .../CenteredProjectiveTransformProcessor.cs | 40 ---- .../InterpolatedTransformProcessorBase.cs | 116 ----------- .../ProjectiveTransformProcessor.cs | 197 +++++------------- .../Processors/Transforms/TransformHelpers.cs | 138 ------------ .../Transforms/TransformProcessorBase.cs | 2 +- .../Transforms/TransformProcessorHelpers.cs | 58 ++++++ .../Processors/Transforms/TransformUtils.cs | 162 ++++++++++++++ .../Processing/ProjectiveTransformBuilder.cs | 113 ++++++++++ .../Processing/ProjectiveTransformHelper.cs | 166 --------------- src/ImageSharp/Processing/TaperCorner.cs | 26 +++ src/ImageSharp/Processing/TaperSide.cs | 31 +++ .../Processing/TransformExtensions.cs | 40 +--- .../Transforms/AffineTransformTests.cs | 2 +- .../Transforms/ProjectiveTransformTests.cs | 27 +-- .../Transforms/TransformsHelpersTest.cs | 2 +- 17 files changed, 475 insertions(+), 661 deletions(-) delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs create mode 100644 src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs create mode 100644 src/ImageSharp/Processing/ProjectiveTransformBuilder.cs delete mode 100644 src/ImageSharp/Processing/ProjectiveTransformHelper.cs create mode 100644 src/ImageSharp/Processing/TaperCorner.cs create mode 100644 src/ImageSharp/Processing/TaperSide.cs diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index e5ce1450f7..ff44915b14 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -30,6 +30,11 @@ namespace SixLabors.ImageSharp.Processing : this(sourceRectangle.Size) => this.rectangle = sourceRectangle; + /// + /// Gets the source image size. + /// + internal Size Size { get; } + /// /// Prepends a centered rotation matrix using the given rotation in degrees. /// @@ -41,11 +46,6 @@ namespace SixLabors.ImageSharp.Processing return this; } - /// - /// Gets the source image size. - /// - internal Size Size { get; } - /// /// Appends a centered rotation matrix using the given rotation in degrees. /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index fb42b83341..2370adb862 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -22,9 +22,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// - /// The transform matrix + /// The transform matrix. /// The sampler to perform the transform operation. - /// The source image size + /// The source image size. public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize) { Guard.NotNull(sampler, nameof(sampler)); @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Configuration configuration) { // Handle tranforms that result in output identical to the original. - if (this.TransformMatrix.Equals(Matrix3x2.Identity)) + if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix3x2.Identity)) { // The cloned will be blank here copy all the pixel data over source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs deleted file mode 100644 index 962b9e4c9d..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// A base class that provides methods to allow the automatic centering of non-affine transforms - /// - /// The pixel format. - internal abstract class CenteredProjectiveTransformProcessor : ProjectiveTransformProcessor - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The transform matrix - /// The sampler to perform the transform operation. - /// The source image size - protected CenteredProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size sourceSize) - : base(matrix, sampler, GetTransformedDimensions(sourceSize, matrix)) - { - } - - /// - protected override Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - { - return TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix); - } - - private static Size GetTransformedDimensions(Size sourceDimensions, Matrix4x4 matrix) - { - var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height); - return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix).Size; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs b/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs deleted file mode 100644 index 4737a4102c..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// The base class for performing interpolated affine and non-affine transforms. - /// - /// The pixel format. - internal abstract class InterpolatedTransformProcessorBase : TransformProcessorBase - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The sampler to perform the transform operation. - protected InterpolatedTransformProcessorBase(IResampler sampler) - { - Guard.NotNull(sampler, nameof(sampler)); - this.Sampler = sampler; - } - - /// - /// Gets the sampler to perform interpolation of the transform operation. - /// - public IResampler Sampler { get; } - - /// - /// Calculated the weights for the given point. - /// This method uses more samples than the upscaled version to ensure edge pixels are correctly rendered. - /// Additionally the weights are normalized. - /// - /// The minimum sampling offset - /// The maximum sampling offset - /// The minimum source bounds - /// The maximum source bounds - /// The transformed point dimension - /// The sampler - /// The transformed image scale relative to the source - /// The reference to the collection of weights - /// The length of the weights collection - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected static void CalculateWeightsDown(int min, int max, int sourceMin, int sourceMax, float point, IResampler sampler, float scale, ref float weightsRef, int length) - { - float sum = 0; - - // Downsampling weights requires more edge sampling plus normalization of the weights - for (int x = 0, i = min; i <= max; i++, x++) - { - int index = i; - if (index < sourceMin) - { - index = sourceMin; - } - - if (index > sourceMax) - { - index = sourceMax; - } - - float weight = sampler.GetValue((index - point) / scale); - sum += weight; - Unsafe.Add(ref weightsRef, x) = weight; - } - - if (sum > 0) - { - for (int i = 0; i < length; i++) - { - ref float wRef = ref Unsafe.Add(ref weightsRef, i); - wRef /= sum; - } - } - } - - /// - /// Calculated the weights for the given point. - /// - /// The minimum source bounds - /// The maximum source bounds - /// The transformed point dimension - /// The sampler - /// The reference to the collection of weights - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected static void CalculateWeightsScaleUp(int sourceMin, int sourceMax, float point, IResampler sampler, ref float weightsRef) - { - for (int x = 0, i = sourceMin; i <= sourceMax; i++, x++) - { - Unsafe.Add(ref weightsRef, x) = sampler.GetValue(i - point); - } - } - - /// - /// Calculates the sampling radius for the current sampler - /// - /// The source dimension size - /// The destination dimension size - /// The radius, and scaling factor - protected (float radius, float scale, float ratio) GetSamplingRadius(int sourceSize, int destinationSize) - { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; - - if (scale < 1F) - { - scale = 1F; - } - - return (MathF.Ceiling(scale * this.Sampler.Radius), scale, ratio); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 50af26aebf..bfde1769c1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -5,13 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -20,22 +16,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides the base methods to perform non-affine transforms on an image. /// /// The pixel format. - internal class ProjectiveTransformProcessor : InterpolatedTransformProcessorBase + internal class ProjectiveTransformProcessor : TransformProcessorBase where TPixel : struct, IPixel { /// /// Initializes a new instance of the class. /// - /// The transform matrix + /// The transform matrix. /// The sampler to perform the transform operation. - /// The target dimensions to constrain the transformed image to. - public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size targetDimensions) - : base(sampler) + /// The source image size. + public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size sourceSize) { + Guard.NotNull(sampler, nameof(sampler)); + this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = targetDimensions; + this.TargetDimensions = TransformUtils.GetTransformedSize(sourceSize, matrix); } + /// + /// Gets the sampler to perform interpolation of the transform operation. + /// + public IResampler Sampler { get; } + /// /// Gets the matrix used to supply the projective transform /// @@ -60,17 +62,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// protected override void OnFrameApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) { + // Handle tranforms that result in output identical to the original. + if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix4x4.Identity)) + { + // The cloned will be blank here copy all the pixel data over + source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); + return; + } + int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; - Rectangle sourceBounds = source.Bounds(); - var targetBounds = new Rectangle(0, 0, width, height); - - // Since could potentially be resizing the canvas we might need to re-calculate the matrix - Matrix4x4 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); + var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. - Matrix4x4.Invert(matrix, out matrix); + Matrix4x4.Invert(this.TransformMatrix, out Matrix4x4 matrix); const float Epsilon = 0.0000001F; if (this.Sampler is NearestNeighborResampler) @@ -92,7 +98,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int px = (int)MathF.Round(v3.X / z); int py = (int)MathF.Round(v3.Y / z); - if (sourceBounds.Contains(px, py)) + if (sourceRectangle.Contains(px, py)) { destRow[x] = source[px, py]; } @@ -103,145 +109,40 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - int maxSourceX = source.Width - 1; - int maxSourceY = source.Height - 1; - (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); - (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - float xScale = xRadiusScale.scale; - float yScale = yRadiusScale.scale; - - // Using Vector4 with dummy 0-s, because Vector2 SIMD implementation is not reliable: - var radius = new Vector4(xRadiusScale.radius, yRadiusScale.radius, 0, 0); - - IResampler sampler = this.Sampler; - var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); - int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); - int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); - - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) - using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) + var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler); + try { - ParallelHelper.IterateRows( + ParallelHelper.IterateRowsWithTempBuffer( targetBounds, configuration, - rows => + (rows, vectorBuffer) => + { + Span vectorSpan = vectorBuffer.Span; + for (int y = rows.Min; y < rows.Max; y++) { - for (int y = rows.Min; y < rows.Max; y++) - { - ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); - ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); - - for (int x = 0; x < width; x++) - { - // Use the single precision position to calculate correct bounding pixels - // otherwise we get rogue pixels outside of the bounds. - var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix); - float z = MathF.Max(v3.Z, Epsilon); - - // Using Vector4 with dummy 0-s, because Vector2 SIMD implementation is not reliable: - Vector4 point = new Vector4(v3.X, v3.Y, 0, 0) / z; - - // Clamp sampling pixel radial extents to the source image edges - Vector4 maxXY = point + radius; - Vector4 minXY = point - radius; - - // max, maxY, minX, minY - var extents = new Vector4( - MathF.Floor(maxXY.X + .5F), - MathF.Floor(maxXY.Y + .5F), - MathF.Ceiling(minXY.X - .5F), - MathF.Ceiling(minXY.Y - .5F)); - - int right = (int)extents.X; - int bottom = (int)extents.Y; - int left = (int)extents.Z; - int top = (int)extents.W; + Span targetRowSpan = destination.GetPixelRowSpan(y); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan, vectorSpan); + ref float ySpanRef = ref kernel.GetYStartReference(y); + ref float xSpanRef = ref kernel.GetXStartReference(y); - extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); - - int maxX = (int)extents.X; - int maxY = (int)extents.Y; - int minX = (int)extents.Z; - int minY = (int)extents.W; - - if (minX == maxX || minY == maxY) - { - continue; - } - - // It appears these have to be calculated on-the-fly. - // Precalulating transformed weights would require prior knowledge of every transformed pixel location - // since they can be at sub-pixel positions on both axis. - // I've optimized where I can but am always open to suggestions. - if (yScale > 1 && xScale > 1) - { - CalculateWeightsDown( - top, - bottom, - minY, - maxY, - point.Y, - sampler, - yScale, - ref ySpanRef, - yLength); - - CalculateWeightsDown( - left, - right, - minX, - maxX, - point.X, - sampler, - xScale, - ref xSpanRef, - xLength); - } - else - { - CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); - CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); - } - - // Now multiply the results against the offsets - Vector4 sum = Vector4.Zero; - for (int yy = 0, j = minY; j <= maxY; j++, yy++) - { - float yWeight = Unsafe.Add(ref ySpanRef, yy); - - for (int xx = 0, i = minX; i <= maxX; i++, xx++) - { - float xWeight = Unsafe.Add(ref xSpanRef, xx); - - // Values are first premultiplied to prevent darkening of edge pixels - var current = source[i, j].ToVector4(); - Vector4Utils.Premultiply(ref current); - sum += current * xWeight * yWeight; - } - } - - ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); + for (int x = 0; x < width; x++) + { + // Use the single precision position to calculate correct bounding pixels + // otherwise we get rogue pixels outside of the bounds. + var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix); + Vector2 point = new Vector2(v3.X, v3.Y) / MathF.Max(v3.Z, Epsilon); - // Reverse the premultiplication - Vector4Utils.UnPremultiply(ref sum); - dest.FromVector4(sum); - } + kernel.Convolve(point, x, ref ySpanRef, ref xSpanRef, source.PixelBuffer, vectorSpan); } - }); + + PixelOperations.Instance.FromVector4(configuration, vectorSpan, targetRowSpan); + } + }); + } + finally + { + kernel.Dispose(); } } - - /// - /// Gets a transform matrix adjusted for final processing based upon the target image bounds. - /// - /// The source image bounds. - /// The destination image bounds. - /// - /// The . - /// - protected virtual Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) => this.TransformMatrix; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs deleted file mode 100644 index 2e85f6c2cc..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.MetaData.Profiles.Exif; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// Contains helper methods for working with affine and non-affine transforms - /// - internal static class TransformHelpers - { - /// - /// Updates the dimensional metadata of a transformed image - /// - /// The pixel format. - /// The image to update - public static void UpdateDimensionalMetData(Image image) - where TPixel : struct, IPixel - { - ExifProfile profile = image.MetaData.ExifProfile; - if (profile is null) - { - return; - } - - // Removing the previously stored value allows us to set a value with our own data tag if required. - if (profile.GetValue(ExifTag.PixelXDimension) != null) - { - profile.RemoveValue(ExifTag.PixelXDimension); - - if (image.Width <= ushort.MaxValue) - { - profile.SetValue(ExifTag.PixelXDimension, (ushort)image.Width); - } - else - { - profile.SetValue(ExifTag.PixelXDimension, (uint)image.Width); - } - } - - if (profile.GetValue(ExifTag.PixelYDimension) != null) - { - profile.RemoveValue(ExifTag.PixelYDimension); - - if (image.Height <= ushort.MaxValue) - { - profile.SetValue(ExifTag.PixelYDimension, (ushort)image.Height); - } - else - { - profile.SetValue(ExifTag.PixelYDimension, (uint)image.Height); - } - } - } - - /// - /// Gets the centered transform matrix based upon the source and destination rectangles - /// - /// The source image bounds. - /// The destination image bounds. - /// The transformation matrix. - /// The - public static Matrix3x2 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix3x2 matrix) - { - // We invert the matrix to handle the transformation from screen to world space. - // This ensures scaling matrices are correct. - Matrix3x2.Invert(matrix, out Matrix3x2 inverted); - - var translationToTargetCenter = Matrix3x2.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F); - var translateToSourceCenter = Matrix3x2.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F); - - Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); - - // Translate back to world to pass to the Transform method. - return centered; - } - - /// - /// Gets the centered transform matrix based upon the source and destination rectangles - /// - /// The source image bounds. - /// The destination image bounds. - /// The transformation matrix. - /// The - public static Matrix4x4 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix4x4 matrix) - { - // We invert the matrix to handle the transformation from screen to world space. - // This ensures scaling matrices are correct. - Matrix4x4.Invert(matrix, out Matrix4x4 inverted); - - var translationToTargetCenter = Matrix4x4.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F, 0); - var translateToSourceCenter = Matrix4x4.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F, 0); - - Matrix4x4.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix4x4 centered); - - // Translate back to world to pass to the Transform method. - return centered; - } - - /// - /// Returns the bounding rectangle relative to the source for the given transformation matrix. - /// - /// The source rectangle. - /// The transformation matrix. - /// - /// The . - /// - public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix4x4 matrix) - { - // Calculate the position of the four corners in world space by applying - // The world matrix to the four corners in object space (0, 0, width, height) - var tl = Vector2.Transform(Vector2.Zero, matrix); - var tr = Vector2.Transform(new Vector2(rectangle.Width, 0), matrix); - var bl = Vector2.Transform(new Vector2(0, rectangle.Height), matrix); - var br = Vector2.Transform(new Vector2(rectangle.Width, rectangle.Height), matrix); - - return GetBoundingRectangle(tl, tr, bl, br); - } - - private static Rectangle GetBoundingRectangle(Vector2 tl, Vector2 tr, Vector2 bl, Vector2 br) - { - // Find the minimum and maximum "corners" based on the given vectors - float minX = MathF.Min(tl.X, MathF.Min(tr.X, MathF.Min(bl.X, br.X))); - float maxX = MathF.Max(tl.X, MathF.Max(tr.X, MathF.Max(bl.X, br.X))); - float minY = MathF.Min(tl.Y, MathF.Min(tr.Y, MathF.Min(bl.Y, br.Y))); - float maxY = MathF.Max(tl.Y, MathF.Max(tr.Y, MathF.Max(bl.Y, br.Y))); - float sizeX = maxX - minX + .5F; - float sizeY = maxY - minY + .5F; - - return new Rectangle((int)(MathF.Ceiling(minX) - .5F), (int)(MathF.Ceiling(minY) - .5F), (int)MathF.Floor(sizeX), (int)MathF.Floor(sizeY)); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs index 13ee90a062..4973b90f46 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs @@ -16,6 +16,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// protected override void AfterImageApply(Image source, Image destination, Rectangle sourceRectangle) - => TransformHelpers.UpdateDimensionalMetData(destination); + => TransformProcessorHelpers.UpdateDimensionalMetData(destination); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs new file mode 100644 index 0000000000..f5536d0467 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs @@ -0,0 +1,58 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData.Profiles.Exif; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains helper methods for working with transforms. + /// + internal static class TransformProcessorHelpers + { + /// + /// Updates the dimensional metadata of a transformed image + /// + /// The pixel format. + /// The image to update + public static void UpdateDimensionalMetData(Image image) + where TPixel : struct, IPixel + { + ExifProfile profile = image.MetaData.ExifProfile; + if (profile is null) + { + return; + } + + // Removing the previously stored value allows us to set a value with our own data tag if required. + if (profile.GetValue(ExifTag.PixelXDimension) != null) + { + profile.RemoveValue(ExifTag.PixelXDimension); + + if (image.Width <= ushort.MaxValue) + { + profile.SetValue(ExifTag.PixelXDimension, (ushort)image.Width); + } + else + { + profile.SetValue(ExifTag.PixelXDimension, (uint)image.Width); + } + } + + if (profile.GetValue(ExifTag.PixelYDimension) != null) + { + profile.RemoveValue(ExifTag.PixelYDimension); + + if (image.Height <= ushort.MaxValue) + { + profile.SetValue(ExifTag.PixelYDimension, (ushort)image.Height); + } + else + { + profile.SetValue(ExifTag.PixelYDimension, (uint)image.Height); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs index 10cf49c34b..f561d3513f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -58,6 +58,111 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return centered; } + /// + /// Creates a matrix that performs a tapering projective transform. + /// + /// + /// The rectangular size of the image being transformed. + /// An enumeration that indicates the side of the rectangle that tapers. + /// An enumeration that indicates on which corners to taper the rectangle. + /// The amount to taper. + /// The + public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner corner, float fraction) + { + Matrix4x4 matrix = Matrix4x4.Identity; + + switch (side) + { + case TaperSide.Left: + matrix.M11 = fraction; + matrix.M22 = fraction; + matrix.M13 = (fraction - 1) / size.Width; + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M12 = size.Height * matrix.M13; + matrix.M32 = size.Height * (1 - fraction); + break; + + case TaperCorner.Both: + matrix.M12 = size.Height * .5F * matrix.M13; + matrix.M32 = size.Height * (1 - fraction) / 2; + break; + } + + break; + + case TaperSide.Top: + matrix.M11 = fraction; + matrix.M22 = fraction; + matrix.M23 = (fraction - 1) / size.Height; + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M21 = size.Width * matrix.M23; + matrix.M31 = size.Width * (1 - fraction); + break; + + case TaperCorner.Both: + matrix.M21 = size.Width * .5F * matrix.M23; + matrix.M31 = size.Width * (1 - fraction) / 2; + break; + } + + break; + + case TaperSide.Right: + matrix.M11 = 1 / fraction; + matrix.M13 = (1 - fraction) / (size.Width * fraction); + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M12 = size.Height * matrix.M13; + break; + + case TaperCorner.Both: + matrix.M12 = size.Height * .5F * matrix.M13; + break; + } + + break; + + case TaperSide.Bottom: + matrix.M22 = 1 / fraction; + matrix.M23 = (1 - fraction) / (size.Height * fraction); + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M21 = size.Width * matrix.M23; + break; + + case TaperCorner.Both: + matrix.M21 = size.Width * .5F * matrix.M23; + break; + } + + break; + } + + return matrix; + } + /// /// Returns the rectangle bounds relative to the source for the given transformation matrix. /// @@ -114,6 +219,63 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Rectangle rectangle = GetTransformedRectangle(new Rectangle(Point.Empty, size), matrix); + return ConstrainSize(rectangle); + } + + /// + /// Returns the rectangle relative to the source for the given transformation matrix. + /// + /// The source rectangle. + /// The transformation matrix. + /// + /// The . + /// + public static Rectangle GetTransformedRectangle(Rectangle rectangle, Matrix4x4 matrix) + { + if (rectangle.Equals(default) || Matrix4x4.Identity.Equals(matrix)) + { + return rectangle; + } + + Vector2 GetVector(float x, float y) + { + const float Epsilon = 0.0000001F; + var v3 = Vector3.Transform(new Vector3(x, y, 1F), matrix); + return new Vector2(v3.X, v3.Y) / MathF.Max(v3.Z, Epsilon); + } + + Vector2 tl = GetVector(rectangle.Left, rectangle.Top); + Vector2 tr = GetVector(rectangle.Right, rectangle.Top); + Vector2 bl = GetVector(rectangle.Left, rectangle.Bottom); + Vector2 br = GetVector(rectangle.Right, rectangle.Bottom); + + return GetBoundingRectangle(tl, tr, bl, br); + } + + /// + /// Returns the size relative to the source for the given transformation matrix. + /// + /// The source size. + /// The transformation matrix. + /// + /// The . + /// + public static Size GetTransformedSize(Size size, Matrix4x4 matrix) + { + Guard.IsTrue(size.Width > 0 && size.Height > 0, nameof(size), "Source size dimensions cannot be 0!"); + + if (matrix.Equals(default) || matrix.Equals(Matrix4x4.Identity)) + { + return size; + } + + Rectangle rectangle = GetTransformedRectangle(new Rectangle(Point.Empty, size), matrix); + + return ConstrainSize(rectangle); + } + + private static Size ConstrainSize(Rectangle rectangle) + { // We want to resize the canvas here taking into account any translations. int height = rectangle.Top < 0 ? rectangle.Bottom : Math.Max(rectangle.Height, rectangle.Bottom); int width = rectangle.Left < 0 ? rectangle.Right : Math.Max(rectangle.Width, rectangle.Right); diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs new file mode 100644 index 0000000000..3edc993c47 --- /dev/null +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -0,0 +1,113 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using System.Numerics; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// A helper class for constructing instances for use in projective transforms. + /// + public class ProjectiveTransformBuilder + { + private readonly List matrices = new List(); + private Rectangle rectangle; + + /// + /// Initializes a new instance of the class. + /// + /// The source image size. + public ProjectiveTransformBuilder(Size sourceSize) => this.Size = sourceSize; + + /// + /// Initializes a new instance of the class. + /// + /// The source rectangle. + public ProjectiveTransformBuilder(Rectangle sourceRectangle) + : this(sourceRectangle.Size) + => this.rectangle = sourceRectangle; + + /// + /// Gets the source image size. + /// + internal Size Size { get; } + + /// + /// Prepends a matrix that performs a tapering projective transform. + /// + /// An enumeration that indicates the side of the rectangle that tapers. + /// An enumeration that indicates on which corners to taper the rectangle. + /// The amount to taper. + /// The . + public ProjectiveTransformBuilder PrependTaperMatrix(TaperSide side, TaperCorner corner, float fraction) + { + this.matrices.Insert(0, TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + return this; + } + + /// + /// Appends a matrix that performs a tapering projective transform. + /// + /// An enumeration that indicates the side of the rectangle that tapers. + /// An enumeration that indicates on which corners to taper the rectangle. + /// The amount to taper. + /// The . + public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) + { + this.matrices.Add(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + return this; + } + + /// + /// Prepends a raw matrix. + /// + /// The matrix to prepend. + /// The . + public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) + { + this.matrices.Insert(0, matrix); + return this; + } + + /// + /// Appends a raw matrix. + /// + /// The matrix to append. + /// The . + public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) + { + this.matrices.Add(matrix); + return this; + } + + /// + /// Returns the combined matrix. + /// + /// The . + public Matrix4x4 BuildMatrix() + { + Matrix4x4 matrix = Matrix4x4.Identity; + + // Translate the origin matrix to cater for source rectangle offsets. + if (!this.rectangle.Equals(default)) + { + matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.rectangle.Location, 0)); + } + + foreach (Matrix4x4 m in this.matrices) + { + matrix *= m; + } + + return matrix; + } + + /// + /// Removes all matrices from the builder. + /// + public void Clear() => this.matrices.Clear(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/ProjectiveTransformHelper.cs b/src/ImageSharp/Processing/ProjectiveTransformHelper.cs deleted file mode 100644 index 4057ec586c..0000000000 --- a/src/ImageSharp/Processing/ProjectiveTransformHelper.cs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing -{ - /// - /// Enumerates the various options which determine which side to taper - /// - public enum TaperSide - { - /// - /// Taper the left side - /// - Left, - - /// - /// Taper the top side - /// - Top, - - /// - /// Taper the right side - /// - Right, - - /// - /// Taper the bottom side - /// - Bottom - } - - /// - /// Enumerates the various options which determine how to taper corners - /// - public enum TaperCorner - { - /// - /// Taper the left or top corner - /// - LeftOrTop, - - /// - /// Taper the right or bottom corner - /// - RightOrBottom, - - /// - /// Taper the both sets of corners - /// - Both - } - - /// - /// Provides helper methods for working with generalized projective transforms. - /// - public static class ProjectiveTransformHelper - { - /// - /// Creates a matrix that performs a tapering projective transform. - /// - /// - /// The rectangular size of the image being transformed. - /// An enumeration that indicates the side of the rectangle that tapers. - /// An enumeration that indicates on which corners to taper the rectangle. - /// The amount to taper. - /// The - public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide taperSide, TaperCorner taperCorner, float taperFraction) - { - Matrix4x4 matrix = Matrix4x4.Identity; - - switch (taperSide) - { - case TaperSide.Left: - matrix.M11 = taperFraction; - matrix.M22 = taperFraction; - matrix.M13 = (taperFraction - 1) / size.Width; - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M12 = size.Height * matrix.M13; - matrix.M32 = size.Height * (1 - taperFraction); - break; - - case TaperCorner.Both: - matrix.M12 = (size.Height * 0.5f) * matrix.M13; - matrix.M32 = size.Height * (1 - taperFraction) / 2; - break; - } - - break; - - case TaperSide.Top: - matrix.M11 = taperFraction; - matrix.M22 = taperFraction; - matrix.M23 = (taperFraction - 1) / size.Height; - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M21 = size.Width * matrix.M23; - matrix.M31 = size.Width * (1 - taperFraction); - break; - - case TaperCorner.Both: - matrix.M21 = (size.Width * 0.5f) * matrix.M23; - matrix.M31 = size.Width * (1 - taperFraction) / 2; - break; - } - - break; - - case TaperSide.Right: - matrix.M11 = 1 / taperFraction; - matrix.M13 = (1 - taperFraction) / (size.Width * taperFraction); - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M12 = size.Height * matrix.M13; - break; - - case TaperCorner.Both: - matrix.M12 = (size.Height * 0.5f) * matrix.M13; - break; - } - - break; - - case TaperSide.Bottom: - matrix.M22 = 1 / taperFraction; - matrix.M23 = (1 - taperFraction) / (size.Height * taperFraction); - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M21 = size.Width * matrix.M23; - break; - - case TaperCorner.Both: - matrix.M21 = (size.Width * 0.5f) * matrix.M23; - break; - } - - break; - } - - return matrix; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/TaperCorner.cs b/src/ImageSharp/Processing/TaperCorner.cs new file mode 100644 index 0000000000..395b171424 --- /dev/null +++ b/src/ImageSharp/Processing/TaperCorner.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// Enumerates the various options which determine how to taper corners + /// + public enum TaperCorner + { + /// + /// Taper the left or top corner + /// + LeftOrTop, + + /// + /// Taper the right or bottom corner + /// + RightOrBottom, + + /// + /// Taper the both sets of corners + /// + Both + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/TaperSide.cs b/src/ImageSharp/Processing/TaperSide.cs new file mode 100644 index 0000000000..226d11aed2 --- /dev/null +++ b/src/ImageSharp/Processing/TaperSide.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// Enumerates the various options which determine which side to taper + /// + public enum TaperSide + { + /// + /// Taper the left side + /// + Left, + + /// + /// Taper the top side + /// + Top, + + /// + /// Taper the right side + /// + Right, + + /// + /// Taper the bottom side + /// + Bottom + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index 4cbd1b041f..ea789eb3d7 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -1,10 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Transforms; -using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing { @@ -14,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing public static class TransformExtensions { /// - /// Transforms an image by the given matrix. + /// Performs an affine transform of an image. /// /// The pixel format. /// The image to transform. @@ -25,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing => Transform(source, builder, KnownResamplers.Bicubic); /// - /// Transforms an image by the given matrix using the specified sampling algorithm. + /// Performs an affine transform of an image using the specified sampling algorithm. /// /// The pixel format. /// The image to transform. @@ -37,44 +35,26 @@ namespace SixLabors.ImageSharp.Processing => source.ApplyProcessor(new AffineTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); /// - /// Transforms an image by the given matrix. + /// Performs a projective transform of an image. /// /// The pixel format. /// The image to transform. - /// The transformation matrix. - /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix) - where TPixel : struct, IPixel - => Transform(source, matrix, KnownResamplers.Bicubic); - - /// - /// Applies a projective transform to the image by the given matrix using the specified sampling algorithm. - /// - /// The pixel format. - /// The image to transform. - /// The transformation matrix. - /// The to perform the resampling. + /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix, IResampler sampler) + public static IImageProcessingContext Transform(this IImageProcessingContext source, ProjectiveTransformBuilder builder) where TPixel : struct, IPixel - => source.ApplyProcessor(new ProjectiveTransformProcessor(matrix, sampler, source.GetCurrentSize())); + => Transform(source, builder, KnownResamplers.Bicubic); /// - /// Applies a projective transform to the image by the given matrix using the specified sampling algorithm. - /// TODO: Should we be offsetting the matrix here? + /// Performs a projective transform of an image using the specified sampling algorithm. /// /// The pixel format. /// The image to transform. - /// The transformation matrix. + /// The projective transform builder. /// The to perform the resampling. - /// The rectangle to constrain the transformed image to. /// The - internal static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix, IResampler sampler, Rectangle rectangle) + public static IImageProcessingContext Transform(this IImageProcessingContext source, ProjectiveTransformBuilder builder, IResampler sampler) where TPixel : struct, IPixel - { - var t = Matrix4x4.CreateTranslation(new Vector3(-rectangle.Location, 0)); - Matrix4x4 combinedMatrix = t * matrix; - return source.ApplyProcessor(new ProjectiveTransformProcessor(combinedMatrix, sampler, rectangle.Size)); - } + => source.ApplyProcessor(new ProjectiveTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 32280d48cd..e05a8e381b 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees((float)Math.PI / 4F); + .AppendRotateMatrixDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index 5190a71e71..0362d75a0b 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms private static readonly ImageComparer TolerantComparer = ImageComparer.TolerantPercentage(0.5f, 3); private ITestOutputHelper Output { get; } - + public static readonly TheoryData ResamplerNames = new TheoryData { nameof(KnownResamplers.Bicubic), @@ -60,10 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms }; - public ProjectiveTransformTests(ITestOutputHelper output) - { - this.Output = output; - } + public ProjectiveTransformTests(ITestOutputHelper output) => this.Output = output; [Theory] [WithTestPatternImages(nameof(ResamplerNames), 150, 150, PixelTypes.Rgba32)] @@ -73,9 +70,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - Matrix4x4 m = ProjectiveTransformHelper.CreateTaperMatrix(image.Size(), TaperSide.Right, TaperCorner.Both, .5F); + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + .AppendTaperMatrix(TaperSide.Right, TaperCorner.Both, .5F); - image.Mutate(i => { i.Transform(m, sampler); }); + image.Mutate(i => i.Transform(builder, sampler)); image.DebugSave(provider, resamplerName); image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); @@ -89,8 +87,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - Matrix4x4 m = ProjectiveTransformHelper.CreateTaperMatrix(image.Size(), taperSide, taperCorner, .5F); - image.Mutate(i => { i.Transform(m); }); + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + .AppendTaperMatrix(taperSide, taperCorner, .5F); + + image.Mutate(i => i.Transform(builder)); FormattableString testOutputDetails = $"{taperSide}-{taperCorner}"; image.DebugSave(provider, testOutputDetails); @@ -110,10 +110,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms // https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/non-affine using (Image image = provider.GetImage()) { - Matrix4x4 m = Matrix4x4.Identity; - m.M13 = 0.01F; + Matrix4x4 matrix = Matrix4x4.Identity; + matrix.M13 = 0.01F; + + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + .AppendMatrix(matrix); - image.Mutate(i => { i.Transform(m); }); + image.Mutate(i => i.Transform(builder)); image.DebugSave(provider); image.CompareToReferenceOutput(TolerantComparer, provider); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs index 146ed62304..909e505357 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelXDimension).DataType); Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelYDimension).DataType); - TransformHelpers.UpdateDimensionalMetData(img); + TransformProcessorHelpers.UpdateDimensionalMetData(img); Assert.Equal(ExifDataType.Short, profile.GetValue(ExifTag.PixelXDimension).DataType); Assert.Equal(ExifDataType.Short, profile.GetValue(ExifTag.PixelYDimension).DataType); From 8b0e276de532d4900b722c75099bb3f9d20235ff Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 10 Nov 2018 21:45:02 +0000 Subject: [PATCH 186/238] Update tests/Images/External --- tests/Images/External | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Images/External b/tests/Images/External index ed8a7b0b6f..e7e0f1311d 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit ed8a7b0b6fe1b2e2a7c822aa617103ae31192655 +Subproject commit e7e0f1311d1d585ea8e38efb5a69fca98c44e8a4 From 657f551642a3e2773cf72534a886ffc63241e9dc Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Sat, 10 Nov 2018 17:25:39 -0600 Subject: [PATCH 187/238] ImageSharp-762_Aot-compiling: added simple unit test to check no exceptions are thrown by AotCompiler --- .../Advanced/AotCompilerTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs new file mode 100644 index 0000000000..3d6faa27ec --- /dev/null +++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs @@ -0,0 +1,18 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Advanced +{ + public class AotCompilerTests + { + [Fact] + public void AotCompiler_NoExceptions() + { + AotCompiler.Seed(); + } + } +} From 15093ba8bff157d0daac92e61e87333779eaa91e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 11 Nov 2018 10:24:32 +0000 Subject: [PATCH 188/238] Change tolerance for 32bit framework builds. --- .../Processing/Transforms/AffineTransformTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index e05a8e381b..15b4500bb2 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -17,7 +17,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { private readonly ITestOutputHelper Output; - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0085f, 3); + // 1 byte difference on one color component. + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0134F, 3); /// /// angleDeg, sx, sy, tx, ty From 88da4bcba303c335d457edce326e1640c972e167 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 11 Nov 2018 21:28:53 +0100 Subject: [PATCH 189/238] make code more clear by extracting the ratio to a variable again while keeping it inlined to avoid it in the third case, and while still replacing the division by a multiplication in the second case. --- src/ImageSharp/Processing/ResizeHelper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index 92af89d9e8..aaac7346d7 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -343,13 +343,15 @@ namespace SixLabors.ImageSharp.Processing if (widthDiff < heightDiff) { - destinationHeight = (int)MathF.Round(width * ((float)sourceHeight / sourceWidth)); + float sourceRatio = (float)sourceHeight / sourceWidth; + destinationHeight = (int)MathF.Round(width * sourceRatio); height = destinationHeight; destinationWidth = width; } else if (widthDiff > heightDiff) { - destinationWidth = (int)MathF.Round(height * ((float)sourceWidth / sourceHeight)); + float sourceRatioInverse = (float)sourceWidth / sourceHeight; + destinationWidth = (int)MathF.Round(height * sourceRatioInverse); destinationHeight = height; width = destinationWidth; } From f6618a6f3aeafe0dc14f82993e197d3c99958975 Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sun, 11 Nov 2018 21:30:19 +0100 Subject: [PATCH 190/238] inline percentHeiught and percentWidth as they are used only in one case each --- src/ImageSharp/Processing/ResizeHelper.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index aaac7346d7..3ae632162f 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -333,10 +333,6 @@ namespace SixLabors.ImageSharp.Processing return (new Size(sourceWidth, sourceWidth), new Rectangle(0, 0, sourceWidth, sourceHeight)); } - // Fractional variants for preserving aspect ratio. - float percentHeight = MathF.Abs(height / (float)sourceHeight); - float percentWidth = MathF.Abs(width / (float)sourceWidth); - // Find the shortest distance to go. int widthDiff = sourceWidth - width; int heightDiff = sourceHeight - height; @@ -360,12 +356,14 @@ namespace SixLabors.ImageSharp.Processing if (height > width) { destinationWidth = width; + float percentWidth = MathF.Abs(width / (float)sourceWidth); destinationHeight = (int)MathF.Round(sourceHeight * percentWidth); height = destinationHeight; } else { destinationHeight = height; + float percentHeight = MathF.Abs(height / (float)sourceHeight); destinationWidth = (int)MathF.Round(sourceWidth * percentHeight); width = destinationWidth; } From 13b9e9c596dc6ca02e1f4c52b6bb6607791ab133 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 11 Nov 2018 21:33:39 +0000 Subject: [PATCH 191/238] Improve transform builder coverage --- .../Processing/AffineTransformBuilder.cs | 16 ++++++++-------- .../Processing/ProjectiveTransformBuilder.cs | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index ff44915b14..b2b011264a 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) { - this.matrices.Insert(0, TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); return this; } @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) { - this.matrices.Add(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + this.AppendMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); return this; } @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependScaleMatrix(SizeF scales) { - this.matrices.Insert(0, Matrix3x2Extensions.CreateScale(scales)); + this.PrependMatrix(Matrix3x2Extensions.CreateScale(scales)); return this; } @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendScaleMatrix(SizeF scales) { - this.matrices.Add(Matrix3x2Extensions.CreateScale(scales)); + this.AppendMatrix(Matrix3x2Extensions.CreateScale(scales)); return this; } @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependSkewMatrixDegrees(float degreesX, float degreesY) { - this.matrices.Insert(0, TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); return this; } @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendSkewMatrixDegrees(float degreesX, float degreesY) { - this.matrices.Add(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); return this; } @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependTranslationMatrix(PointF position) { - this.matrices.Insert(0, Matrix3x2Extensions.CreateTranslation(position)); + this.PrependMatrix(Matrix3x2Extensions.CreateTranslation(position)); return this; } @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendTranslationMatrix(PointF position) { - this.matrices.Add(Matrix3x2Extensions.CreateTranslation(position)); + this.AppendMatrix(Matrix3x2Extensions.CreateTranslation(position)); return this; } diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 3edc993c47..529dd56b19 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public ProjectiveTransformBuilder PrependTaperMatrix(TaperSide side, TaperCorner corner, float fraction) { - this.matrices.Insert(0, TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); return this; } @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) { - this.matrices.Add(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); return this; } From 8a47a1894b5d312fb697b1d49d52556fcd63c526 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 11 Nov 2018 22:42:05 +0000 Subject: [PATCH 192/238] Cleanup and add dedicated transform builder tests --- .../Processing/AffineTransformBuilder.cs | 48 ++++------- .../Processing/ProjectiveTransformBuilder.cs | 18 ++--- .../Transforms/AffineTransformBuilderTests.cs | 79 +++++++++++++++++++ .../ProjectiveTransformBuilderTests.cs | 78 ++++++++++++++++++ 4 files changed, 181 insertions(+), 42 deletions(-) create mode 100644 tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs create mode 100644 tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index b2b011264a..003249d6ed 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -20,7 +20,13 @@ namespace SixLabors.ImageSharp.Processing /// Initializes a new instance of the class. /// /// The source image size. - public AffineTransformBuilder(Size sourceSize) => this.Size = sourceSize; + public AffineTransformBuilder(Size sourceSize) + { + Guard.MustBeGreaterThan(sourceSize.Width, 0, nameof(sourceSize)); + Guard.MustBeGreaterThan(sourceSize.Height, 0, nameof(sourceSize)); + + this.Size = sourceSize; + } /// /// Initializes a new instance of the class. @@ -41,10 +47,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) - { - this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); - return this; - } + => this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); /// /// Appends a centered rotation matrix using the given rotation in degrees. @@ -52,10 +55,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) - { - this.AppendMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); - return this; - } + => this.AppendMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); /// /// Prepends a scale matrix from the given vector scale. @@ -63,10 +63,7 @@ namespace SixLabors.ImageSharp.Processing /// The horizontal and vertical scale. /// The . public AffineTransformBuilder PrependScaleMatrix(SizeF scales) - { - this.PrependMatrix(Matrix3x2Extensions.CreateScale(scales)); - return this; - } + => this.PrependMatrix(Matrix3x2Extensions.CreateScale(scales)); /// /// Appends a scale matrix from the given vector scale. @@ -74,10 +71,7 @@ namespace SixLabors.ImageSharp.Processing /// The horizontal and vertical scale. /// The . public AffineTransformBuilder AppendScaleMatrix(SizeF scales) - { - this.AppendMatrix(Matrix3x2Extensions.CreateScale(scales)); - return this; - } + => this.AppendMatrix(Matrix3x2Extensions.CreateScale(scales)); /// /// Prepends a centered skew matrix from the give angles in degrees. @@ -86,10 +80,7 @@ namespace SixLabors.ImageSharp.Processing /// The Y angle, in degrees. /// The . public AffineTransformBuilder PrependSkewMatrixDegrees(float degreesX, float degreesY) - { - this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); - return this; - } + => this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); /// /// Appends a centered skew matrix from the give angles in degrees. @@ -98,10 +89,7 @@ namespace SixLabors.ImageSharp.Processing /// The Y angle, in degrees. /// The . public AffineTransformBuilder AppendSkewMatrixDegrees(float degreesX, float degreesY) - { - this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); - return this; - } + => this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); /// /// Prepends a translation matrix from the given vector. @@ -109,10 +97,7 @@ namespace SixLabors.ImageSharp.Processing /// The translation position. /// The . public AffineTransformBuilder PrependTranslationMatrix(PointF position) - { - this.PrependMatrix(Matrix3x2Extensions.CreateTranslation(position)); - return this; - } + => this.PrependMatrix(Matrix3x2Extensions.CreateTranslation(position)); /// /// Appends a translation matrix from the given vector. @@ -120,10 +105,7 @@ namespace SixLabors.ImageSharp.Processing /// The translation position. /// The . public AffineTransformBuilder AppendTranslationMatrix(PointF position) - { - this.AppendMatrix(Matrix3x2Extensions.CreateTranslation(position)); - return this; - } + => this.AppendMatrix(Matrix3x2Extensions.CreateTranslation(position)); /// /// Prepends a raw matrix. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 529dd56b19..be4c675189 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -20,7 +20,13 @@ namespace SixLabors.ImageSharp.Processing /// Initializes a new instance of the class. /// /// The source image size. - public ProjectiveTransformBuilder(Size sourceSize) => this.Size = sourceSize; + public ProjectiveTransformBuilder(Size sourceSize) + { + Guard.MustBeGreaterThan(sourceSize.Width, 0, nameof(sourceSize)); + Guard.MustBeGreaterThan(sourceSize.Height, 0, nameof(sourceSize)); + + this.Size = sourceSize; + } /// /// Initializes a new instance of the class. @@ -43,10 +49,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount to taper. /// The . public ProjectiveTransformBuilder PrependTaperMatrix(TaperSide side, TaperCorner corner, float fraction) - { - this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); - return this; - } + => this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); /// /// Appends a matrix that performs a tapering projective transform. @@ -56,10 +59,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount to taper. /// The . public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) - { - this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); - return this; - } + => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); /// /// Prepends a raw matrix. diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs new file mode 100644 index 0000000000..eaa51b1296 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Transforms +{ + public class AffineTransformBuilderTests + { + [Fact] + public void ConstructorAssignsProperties() + { + var s = new Size(1, 1); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + Assert.Equal(s, builder.Size); + } + + [Fact] + public void ConstructorThrowsInvalid() + { + Assert.Throws(() => + { + var s = new Size(0, 1); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + }); + + Assert.Throws(() => + { + var s = new Size(1, 0); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + }); + } + + [Fact] + public void AppendPrependOpposite() + { + var rectangle = new Rectangle(-1, -1, 3, 3); + var b1 = new AffineTransformBuilder(rectangle); + var b2 = new AffineTransformBuilder(rectangle); + + const float pi = (float)Math.PI; + + // Forwards + b1.AppendRotateMatrixDegrees(pi) + .AppendSkewMatrixDegrees(pi, pi) + .AppendScaleMatrix(new SizeF(pi, pi)) + .AppendTranslationMatrix(new PointF(pi, pi)); + + // Backwards + b2.PrependTranslationMatrix(new PointF(pi, pi)) + .PrependScaleMatrix(new SizeF(pi, pi)) + .PrependSkewMatrixDegrees(pi, pi) + .PrependRotateMatrixDegrees(pi); + + Assert.Equal(b1.BuildMatrix(), b2.BuildMatrix()); + } + + [Fact] + public void BuilderCanClear() + { + var rectangle = new Rectangle(0, 0, 3, 3); + var builder = new AffineTransformBuilder(rectangle); + Matrix3x2 matrix = Matrix3x2.Identity; + matrix.M31 = (float)Math.PI; + + Assert.Equal(Matrix3x2.Identity, builder.BuildMatrix()); + + builder.AppendMatrix(matrix); + Assert.NotEqual(Matrix3x2.Identity, builder.BuildMatrix()); + + builder.Clear(); + Assert.Equal(Matrix3x2.Identity, builder.BuildMatrix()); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs new file mode 100644 index 0000000000..3dfc42d4f7 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Transforms +{ + public class ProjectiveTransformBuilderTests + { + [Fact] + public void ConstructorAssignsProperties() + { + var s = new Size(1, 1); + var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); + Assert.Equal(s, builder.Size); + } + + [Fact] + public void ConstructorThrowsInvalid() + { + Assert.Throws(() => + { + var s = new Size(0, 1); + var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); + }); + + Assert.Throws(() => + { + var s = new Size(1, 0); + var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); + }); + } + + [Fact] + public void AppendPrependOpposite() + { + var rectangle = new Rectangle(-1, -1, 3, 3); + var b1 = new ProjectiveTransformBuilder(rectangle); + var b2 = new ProjectiveTransformBuilder(rectangle); + + const float pi = (float)Math.PI; + + Matrix4x4 m4 = Matrix4x4.Identity; + m4.M31 = pi; + + // Forwards + b1.AppendMatrix(m4) + .AppendTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi); + + // Backwards + b2.PrependTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi) + .PrependMatrix(m4); + + Assert.Equal(b1.BuildMatrix(), b2.BuildMatrix()); + } + + [Fact] + public void BuilderCanClear() + { + var rectangle = new Rectangle(0, 0, 3, 3); + var builder = new ProjectiveTransformBuilder(rectangle); + Matrix4x4 matrix = Matrix4x4.Identity; + matrix.M31 = (float)Math.PI; + + Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix()); + + builder.AppendMatrix(matrix); + Assert.NotEqual(Matrix4x4.Identity, builder.BuildMatrix()); + + builder.Clear(); + Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix()); + } + } +} From 6558464c7532736d3e4a5cef3eb60ce3332c573e Mon Sep 17 00:00:00 2001 From: Dan Manning Date: Mon, 12 Nov 2018 13:34:17 -0600 Subject: [PATCH 193/238] ImageSharp-762_Aot-compiling: renamed to AotCompilerTools --- src/ImageSharp/Advanced/{AotCompiler.cs => AotCompilerTools.cs} | 2 +- tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/ImageSharp/Advanced/{AotCompiler.cs => AotCompilerTools.cs} (99%) diff --git a/src/ImageSharp/Advanced/AotCompiler.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs similarity index 99% rename from src/ImageSharp/Advanced/AotCompiler.cs rename to src/ImageSharp/Advanced/AotCompilerTools.cs index 406c162ad5..9e7624480d 100644 --- a/src/ImageSharp/Advanced/AotCompiler.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Advanced /// these are caused because not every possible generic instantiation can be determined up front at compile time. /// The Aot Compiler is designed to overcome the limitations of this compiler. /// - public static class AotCompiler + public static class AotCompilerTools { /// /// Seeds the compiler using the given pixel format. diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs index 3d6faa27ec..5c1dd4bb08 100644 --- a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs +++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Advanced [Fact] public void AotCompiler_NoExceptions() { - AotCompiler.Seed(); + AotCompilerTools.Seed(); } } } From 6a81923ab7f57d7d947f826de1ef426bec5806ca Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 12 Nov 2018 20:34:37 +0000 Subject: [PATCH 194/238] Tighten up coverage on new AotCompilerTools --- tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs index 5c1dd4bb08..f6397dbd09 100644 --- a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs +++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs @@ -10,9 +10,6 @@ namespace SixLabors.ImageSharp.Tests.Advanced public class AotCompilerTests { [Fact] - public void AotCompiler_NoExceptions() - { - AotCompilerTools.Seed(); - } + public void AotCompiler_NoExceptions() => AotCompilerTools.Seed(); } } From 1c258dcae42f959e1fcf0cd355f3c2aad63a5bf6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 13 Nov 2018 09:38:57 +0000 Subject: [PATCH 195/238] Update tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs --- .../Processing/Transforms/AffineTransformTests.cs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 15b4500bb2..3d7fba2c19 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -207,21 +207,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms } } - private Matrix3x2 MakeManuallyCenteredMatrix(float angleDeg, float s, Image image) - where TPixel : struct, IPixel - { - Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(angleDeg); - Vector2 toCenter = 0.5f * new Vector2(image.Width, image.Height); - var translate = Matrix3x2.CreateTranslation(-toCenter); - var translateBack = Matrix3x2.CreateTranslation(toCenter); - var scale = Matrix3x2.CreateScale(s); - - Matrix3x2 m = translate * rotate * scale * translateBack; - - this.PrintMatrix(m); - return m; - } - private static IResampler GetResampler(string name) { PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); From 0ac969a711ed043f0586a961b12b4451dc29cbe2 Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Thu, 1 Nov 2018 16:25:55 -0700 Subject: [PATCH 196/238] Optimize filling a region with a solid brush when antialias is off --- .../Processors/Drawing/FillRegionProcessor.cs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 1dc63efa27..170e3d34f2 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -3,7 +3,7 @@ using System; using System.Buffers; - +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; @@ -168,17 +168,31 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { if (!this.Options.Antialias) { + bool hasOnes = false; + bool hasZeros = false; for (int x = 0; x < scanlineWidth; x++) { if (scanline[x] >= 0.5) { scanline[x] = 1; + hasOnes = true; } else { scanline[x] = 0; + hasZeros = true; } } + + if (hasOnes != hasZeros && this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) + { + if (hasOnes) + { + source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrush.Color); + } + + continue; + } } applicator.Apply(scanline, minX, y); @@ -187,5 +201,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing } } } + + private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) + { + solidBrush = this.Brush as SolidBrush; + + if (solidBrush == null) + { + return false; + } + + return this.Options.IsOpaqueColorWithoutBlending(solidBrush.Color); + } } } \ No newline at end of file From 8073404c7773d5808f2372d0c72fe035bc78bb9e Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Thu, 15 Nov 2018 08:55:22 -0800 Subject: [PATCH 197/238] Check for solid brush outside of loops --- .../Processing/Processors/Drawing/FillRegionProcessor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 170e3d34f2..550c021caa 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -107,6 +107,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing Span buffer = bBuffer.GetSpan(); Span scanline = bScanline.GetSpan(); + bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush); + for (int y = minY; y < maxY; y++) { if (scanlineDirty) @@ -184,7 +186,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing } } - if (hasOnes != hasZeros && this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) + if (isSolidBrushWithoutBlending && hasOnes != hasZeros) { if (hasOnes) { From f79f1894a342dae48629c5ea756185f7572af313 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 22 Nov 2018 17:09:48 +0000 Subject: [PATCH 198/238] Reduce allocatoins, check bit depth and rename. --- src/ImageSharp/Formats/Png/PngChunkType.cs | 4 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 6 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 107 ++++++++---------- .../Formats/Png/PngChunkTypeTests.cs | 2 +- .../Formats/Png/PngDecoderTests.Chunks.cs | 2 +- 5 files changed, 56 insertions(+), 65 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs index 7654c17014..1b251a5748 100644 --- a/src/ImageSharp/Formats/Png/PngChunkType.cs +++ b/src/ImageSharp/Formats/Png/PngChunkType.cs @@ -56,10 +56,10 @@ namespace SixLabors.ImageSharp.Formats.Png Text = 0x74455874U, /// - /// This chunk specifies that the image uses simple transparency: + /// The tRNS chunk specifies that the image uses simple transparency: /// either alpha values associated with palette entries (for indexed-color images) /// or a single transparent color (for grayscale and true color images). /// - PaletteAlpha = 0x74524E53U + Transparency = 0x74524E53U } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index c446184d80..9ffac5e626 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Formats.Png Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); this.palette = pal; break; - case PngChunkType.PaletteAlpha: + case PngChunkType.Transparency: byte[] alpha = new byte[chunk.Length]; Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); this.paletteAlpha = alpha; @@ -306,9 +306,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset) - { - return (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); - } + => (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); /// /// Attempts to convert a byte array to a new array where each value in the original array is represented by the diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 532e6f7471..8a31aaf51b 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -292,7 +292,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (pngMetaData.HasTrans) { - this.WriteTransparencyMarkers(stream, pngMetaData); + this.WriteTransparencyChunk(stream, pngMetaData); } this.WritePhysicalChunk(stream, metaData); @@ -305,52 +305,6 @@ namespace SixLabors.ImageSharp.Formats.Png quantized?.Dispose(); } - /// - /// Writes the transparency markers to the stream - /// - /// The containing image data. - /// The image meta data. - private void WriteTransparencyMarkers(Stream stream, PngMetaData pngMetaData) - { - if (pngMetaData.ColorType == PngColorType.Rgb) - { - if (pngMetaData.TransparentRgb48 != null) - { - var r = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R); - var g = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R); - var b = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.B); - - var alphaArray = r.Concat(g).Concat(b).ToArray(); - - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); - } - else if (pngMetaData.TransparentRgb24 != null) - { - var alphaArray = new byte[6]; - alphaArray[1] = pngMetaData.TransparentRgb24.Value.R; - alphaArray[3] = pngMetaData.TransparentRgb24.Value.G; - alphaArray[5] = pngMetaData.TransparentRgb24.Value.B; - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); - } - } - else if (pngMetaData.ColorType == PngColorType.Grayscale) - { - if (pngMetaData.TransparentGray16 != null) - { - var alphaArray = BitConverter.GetBytes(pngMetaData.TransparentGray16.Value.PackedValue); - - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); - } - else if (pngMetaData.TransparentGray8 != null) - { - var alphaArray = new byte[2]; - alphaArray[1] = pngMetaData.TransparentGray8.Value.PackedValue; - - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length); - } - } - } - /// public void Dispose() { @@ -377,7 +331,6 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.pngColorType.Equals(PngColorType.Grayscale)) { - // TODO: Research and add support for grayscale plus tRNS if (this.use16Bit) { // 16 bit grayscale @@ -752,7 +705,7 @@ namespace SixLabors.ImageSharp.Formats.Png // Write the transparency data if (anyAlpha) { - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, paletteLength); + this.WriteChunk(stream, PngChunkType.Transparency, alphaTable.Array, 0, paletteLength); } } } @@ -800,6 +753,52 @@ namespace SixLabors.ImageSharp.Formats.Png } } + /// + /// Writes the transparency chunk to the stream + /// + /// The containing image data. + /// The image meta data. + private void WriteTransparencyChunk(Stream stream, PngMetaData pngMetaData) + { + if (pngMetaData.ColorType.Equals(PngColorType.Rgb)) + { + Span alpha = this.buffer.AsSpan(); + if (pngMetaData.TransparentRgb48.HasValue && this.use16Bit) + { + Rgb48 rgb = pngMetaData.TransparentRgb48.Value; + BinaryPrimitives.WriteUInt16LittleEndian(alpha, rgb.R); + BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G); + BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B); + + this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + } + else if (pngMetaData.TransparentRgb24.HasValue) + { + alpha.Clear(); + Rgb24 rgb = pngMetaData.TransparentRgb24.Value; + alpha[1] = rgb.R; + alpha[3] = rgb.G; + alpha[5] = rgb.B; + this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + } + } + else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale)) + { + Span alpha = this.buffer.AsSpan(); + if (pngMetaData.TransparentGray16.HasValue && this.bitDepth == 16) + { + BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue); + this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + } + else if (pngMetaData.TransparentGray8.HasValue) + { + alpha.Clear(); + alpha[1] = pngMetaData.TransparentGray8.Value.PackedValue; + this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + } + } + } + /// /// Writes the pixel information to the stream. /// @@ -894,10 +893,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// Writes the chunk end to the stream. /// /// The containing image data. - private void WriteEndChunk(Stream stream) - { - this.WriteChunk(stream, PngChunkType.End, null); - } + private void WriteEndChunk(Stream stream) => this.WriteChunk(stream, PngChunkType.End, null); /// /// Writes a chunk to the stream. @@ -905,10 +901,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The to write to. /// The type of chunk to write. /// The containing data. - private void WriteChunk(Stream stream, PngChunkType type, byte[] data) - { - this.WriteChunk(stream, type, data, 0, data?.Length ?? 0); - } + private void WriteChunk(Stream stream, PngChunkType type, byte[] data) => this.WriteChunk(stream, type, data, 0, data?.Length ?? 0); /// /// Writes a chunk of a specified length to the stream at the given offset. diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs index e4cd06ab1b..894d902b78 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Equal(PngChunkType.Palette, GetType("PLTE")); Assert.Equal(PngChunkType.Data, GetType("IDAT")); Assert.Equal(PngChunkType.End, GetType("IEND")); - Assert.Equal(PngChunkType.PaletteAlpha, GetType("tRNS")); + Assert.Equal(PngChunkType.Transparency, GetType("tRNS")); Assert.Equal(PngChunkType.Text, GetType("tEXt")); Assert.Equal(PngChunkType.Gamma, GetType("gAMA")); Assert.Equal(PngChunkType.Physical, GetType("pHYs")); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index 2a7d696164..6a0119f0f1 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [Theory] [InlineData((uint)PngChunkType.Gamma)] // gAMA - [InlineData((uint)PngChunkType.PaletteAlpha)] // tRNS + [InlineData((uint)PngChunkType.Transparency)] // tRNS [InlineData((uint)PngChunkType.Physical)] // pHYs: It's ok to test physical as we don't throw for duplicate chunks. //[InlineData(PngChunkTypes.Text)] //TODO: Figure out how to test this public void Decode_IncorrectCRCForNonCriticalChunk_ExceptionIsThrown(uint chunkType) From ead17fd0179c98b99b3212b9213bcefbf9335e89 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 22 Nov 2018 17:12:43 +0000 Subject: [PATCH 199/238] Use existing field --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 8a31aaf51b..bb800c8a48 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -785,7 +785,7 @@ namespace SixLabors.ImageSharp.Formats.Png else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale)) { Span alpha = this.buffer.AsSpan(); - if (pngMetaData.TransparentGray16.HasValue && this.bitDepth == 16) + if (pngMetaData.TransparentGray16.HasValue && this.use16Bit) { BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue); this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); From 68496170654216571d54261d3f7074b8e9194a45 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 23 Nov 2018 12:25:05 +0000 Subject: [PATCH 200/238] Fix trns preservation and add tests --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 11 ++- src/ImageSharp/Formats/Png/PngMetaData.cs | 5 ++ .../Formats/Png/PngEncoderTests.cs | 67 ++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 3 + tests/Images/Input/Png/gray-2-tRNS.png | Bin 0 -> 265 bytes tests/Images/Input/Png/gray-4-tRNS.png | Bin 0 -> 267 bytes tests/Images/Input/Png/gray-8-tRNS.png | Bin 0 -> 267 bytes 7 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 tests/Images/Input/Png/gray-2-tRNS.png create mode 100644 tests/Images/Input/Png/gray-4-tRNS.png create mode 100644 tests/Images/Input/Png/gray-8-tRNS.png diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index bb800c8a48..292de007ca 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -760,9 +760,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image meta data. private void WriteTransparencyChunk(Stream stream, PngMetaData pngMetaData) { + Span alpha = this.chunkDataBuffer.AsSpan(); if (pngMetaData.ColorType.Equals(PngColorType.Rgb)) { - Span alpha = this.buffer.AsSpan(); if (pngMetaData.TransparentRgb48.HasValue && this.use16Bit) { Rgb48 rgb = pngMetaData.TransparentRgb48.Value; @@ -770,7 +770,7 @@ namespace SixLabors.ImageSharp.Formats.Png BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G); BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B); - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); } else if (pngMetaData.TransparentRgb24.HasValue) { @@ -779,22 +779,21 @@ namespace SixLabors.ImageSharp.Formats.Png alpha[1] = rgb.R; alpha[3] = rgb.G; alpha[5] = rgb.B; - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); } } else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale)) { - Span alpha = this.buffer.AsSpan(); if (pngMetaData.TransparentGray16.HasValue && this.use16Bit) { BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue); - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); } else if (pngMetaData.TransparentGray8.HasValue) { alpha.Clear(); alpha[1] = pngMetaData.TransparentGray8.Value.PackedValue; - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); } } } diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 6a293f770c..d5ab3d2554 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -26,6 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Png this.BitDepth = other.BitDepth; this.ColorType = other.ColorType; this.Gamma = other.Gamma; + this.HasTrans = other.HasTrans; + this.TransparentGray8 = other.TransparentGray8; + this.TransparentGray16 = other.TransparentGray16; + this.TransparentRgb24 = other.TransparentRgb24; + this.TransparentRgb48 = other.TransparentRgb48; } /// diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 5d328db361..9079b15fb0 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -25,6 +25,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { TestImages.Png.Bpp1, PngBitDepth.Bit1 } }; + public static readonly TheoryData PngTrnsFiles = + new TheoryData + { + { TestImages.Png.Gray1BitTrans, PngBitDepth.Bit1, PngColorType.Grayscale }, + { TestImages.Png.Gray2BitTrans, PngBitDepth.Bit2, PngColorType.Grayscale }, + { TestImages.Png.Gray4BitTrans, PngBitDepth.Bit4, PngColorType.Grayscale }, + { TestImages.Png.Gray8BitTrans, PngBitDepth.Bit8, PngColorType.Grayscale }, + { TestImages.Png.GrayTrns16BitInterlaced, PngBitDepth.Bit16, PngColorType.Grayscale }, + { TestImages.Png.Rgb24BppTrans, PngBitDepth.Bit8, PngColorType.Rgb }, + { TestImages.Png.Rgb48BppTrans, PngBitDepth.Bit16, PngColorType.Rgb } + }; + /// /// All types except Palette /// @@ -249,6 +261,61 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [MemberData(nameof(PngTrnsFiles))] + public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) + { + var options = new PngEncoder(); + + var testFile = TestFile.Create(imagePath); + using (Image input = testFile.CreateImage()) + { + PngMetaData inMeta = input.MetaData.GetFormatMetaData(PngFormat.Instance); + Assert.True(inMeta.HasTrans); + + using (var memStream = new MemoryStream()) + { + input.Save(memStream, options); + memStream.Position = 0; + using (var output = Image.Load(memStream)) + { + PngMetaData outMeta = output.MetaData.GetFormatMetaData(PngFormat.Instance); + Assert.True(outMeta.HasTrans); + + switch (pngColorType) + { + case PngColorType.Grayscale: + if (pngBitDepth.Equals(PngBitDepth.Bit16)) + { + Assert.True(outMeta.TransparentGray16.HasValue); + Assert.Equal(inMeta.TransparentGray16, outMeta.TransparentGray16); + } + else + { + Assert.True(outMeta.TransparentGray8.HasValue); + Assert.Equal(inMeta.TransparentGray8, outMeta.TransparentGray8); + } + + break; + case PngColorType.Rgb: + if (pngBitDepth.Equals(PngBitDepth.Bit16)) + { + Assert.True(outMeta.TransparentRgb48.HasValue); + Assert.Equal(inMeta.TransparentRgb48, outMeta.TransparentRgb48); + } + else + { + Assert.True(outMeta.TransparentRgb24.HasValue); + Assert.Equal(inMeta.TransparentRgb24, outMeta.TransparentRgb24); + } + + break; + } + } + } + } + } + private static void TestPngEncoderCore( TestImageProvider provider, PngColorType pngColorType, diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8da458e520..1144a3f7c0 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -46,6 +46,9 @@ namespace SixLabors.ImageSharp.Tests public const string PDSrc = "Png/pd-source.png"; public const string PDDest = "Png/pd-dest.png"; public const string Gray1BitTrans = "Png/gray-1-trns.png"; + public const string Gray2BitTrans = "Png/gray-2-tRNS.png"; + public const string Gray4BitTrans = "Png/gray-4-tRNS.png"; + public const string Gray8BitTrans = "Png/gray-8-tRNS.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/Images/Input/Png/gray-2-tRNS.png b/tests/Images/Input/Png/gray-2-tRNS.png new file mode 100644 index 0000000000000000000000000000000000000000..8e04cb5020cc1ecf62544cb32d5b79c80db9eb55 GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c21SA-yJ@?oEq?k&A{DK)68K?YR2juCLxJHyX z=ND8KWu|A8FsxKCGB7mO0TQMPUile$3eKf@d6{|X8Hu?HPWk0IsYSIV#s7f%N-{$t zN_;YtQ}c>}(hQ6Ysd)?x9M^SweEFIc1X|aBdc-KRJ9m18V9RtbC7#BO-2Ur1W9#j; zlez9mBy!#Etjcre>X=olwIZjW_ui%cf?1oV^|fysu_zijiZ`$`Yrw=Fz( zYoAeHvWEEVQdfX$D4y)I0_Tj_bNTzI@FJ0MksZvXY1vGw-a z$z1m&61i@7R^_>KbOT9H%Gd+$_Bo*Zy%#K^eU$*(yeWi!*+ZLX? zwa=(8SwnpGsmmvLjg7RLZp>J#2DG2Y)5S4_<9c#R2+&W=ml!^t%;`7}6ld^s^>bP0 Hl+XkKeMDTy literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/gray-8-tRNS.png b/tests/Images/Input/Png/gray-8-tRNS.png new file mode 100644 index 0000000000000000000000000000000000000000..842245f1d9f192857edd85f43f2d8d6ca8874c01 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K57&$`wkAjMP?KCsyuhDj#;%@D{=~Y?_KIIn6-IYU;E~gq@uio*>TJG%QoM-uk`SJ+ro3V z_8IjhYlzQ2b@>FZv5{8OjTvjzfcEovx;TbNTux4rdC0)f)WpbSSo>uLP@KWj)z4*} HQ$iB}V~<+M literal 0 HcmV?d00001 From da50180e1c7a2aa34d94d578824deec4ea3e6b0a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 22:52:47 +0100 Subject: [PATCH 201/238] add more tests --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 15 +- .../Processing/AffineTransformBuilder.cs | 35 ++-- .../Processors/Transforms/TransformUtils.cs | 11 ++ .../Transforms/AffineTransformBuilderTests.cs | 67 +++----- .../Transforms/TransformBuilderTestBase.cs | 151 ++++++++++++++++++ .../TestUtilities/ApproximateFloatComparer.cs | 13 +- 6 files changed, 234 insertions(+), 58 deletions(-) create mode 100644 tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index f07ccb03b4..45556741e6 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -22,7 +22,8 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f); + public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => + (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f); /// /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. @@ -32,7 +33,8 @@ namespace SixLabors.ImageSharp /// The blue component. /// The . [MethodImpl(InliningOptions.ShortMethod)] - public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); + public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => + (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); /// /// Scales a value from a 16 bit to it's 8 bit equivalent. @@ -128,6 +130,15 @@ namespace SixLabors.ImageSharp return x & (m - 1); } + /// + /// Converts degrees to radians + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static float ToRadian(float degrees) + { + return degrees * ((float)Math.PI / 180f); + } + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 003249d6ed..4d798f4396 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -14,18 +14,15 @@ namespace SixLabors.ImageSharp.Processing public class AffineTransformBuilder { private readonly List matrices = new List(); - private Rectangle rectangle; + private readonly Rectangle rectangle; /// /// Initializes a new instance of the class. /// /// The source image size. public AffineTransformBuilder(Size sourceSize) + : this(new Rectangle(Point.Empty, sourceSize)) { - Guard.MustBeGreaterThan(sourceSize.Width, 0, nameof(sourceSize)); - Guard.MustBeGreaterThan(sourceSize.Height, 0, nameof(sourceSize)); - - this.Size = sourceSize; } /// @@ -33,13 +30,17 @@ namespace SixLabors.ImageSharp.Processing /// /// The source rectangle. public AffineTransformBuilder(Rectangle sourceRectangle) - : this(sourceRectangle.Size) - => this.rectangle = sourceRectangle; + { + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); + + this.rectangle = sourceRectangle; + } /// /// Gets the source image size. /// - internal Size Size { get; } + internal Size Size => this.rectangle.Size; /// /// Prepends a centered rotation matrix using the given rotation in degrees. @@ -49,13 +50,29 @@ namespace SixLabors.ImageSharp.Processing public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) => this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + /// + /// Prepends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public AffineTransformBuilder PrependRotateMatrixRadians(float radians) + => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + /// /// Appends a centered rotation matrix using the given rotation in degrees. /// /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) - => this.AppendMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + => this.AppendRotateMatrixRadians(ImageMaths.ToRadian(degrees)); + + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public AffineTransformBuilder AppendRotateMatrixRadians(float radians) + => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); /// /// Prepends a scale matrix from the given vector scale. diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs index f561d3513f..6cef38f8fe 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -23,6 +23,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty)); + /// + /// Creates a centered rotation matrix using the given rotation in radians and the source size. + /// + /// The amount of rotation, in radians. + /// The source image size. + /// The . + public static Matrix3x2 CreateRotationMatrixRadians(float radians, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateRotation(radians, PointF.Empty)); + /// /// Creates a centered skew matrix from the give angles in degrees and the source size. /// diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index eaa51b1296..1b4caee14f 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -4,12 +4,13 @@ using System; using System.Numerics; using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Transforms { - public class AffineTransformBuilderTests + public class AffineTransformBuilderTests : TransformBuilderTestBase { [Fact] public void ConstructorAssignsProperties() @@ -23,57 +24,33 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void ConstructorThrowsInvalid() { Assert.Throws(() => - { - var s = new Size(0, 1); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - }); + { + var s = new Size(0, 1); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + }); Assert.Throws(() => - { - var s = new Size(1, 0); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - }); + { + var s = new Size(1, 0); + var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); + }); } - [Fact] - public void AppendPrependOpposite() - { - var rectangle = new Rectangle(-1, -1, 3, 3); - var b1 = new AffineTransformBuilder(rectangle); - var b2 = new AffineTransformBuilder(rectangle); - - const float pi = (float)Math.PI; - - // Forwards - b1.AppendRotateMatrixDegrees(pi) - .AppendSkewMatrixDegrees(pi, pi) - .AppendScaleMatrix(new SizeF(pi, pi)) - .AppendTranslationMatrix(new PointF(pi, pi)); - - // Backwards - b2.PrependTranslationMatrix(new PointF(pi, pi)) - .PrependScaleMatrix(new SizeF(pi, pi)) - .PrependSkewMatrixDegrees(pi, pi) - .PrependRotateMatrixDegrees(pi); + protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslationMatrix(translate); + protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScaleMatrix(scale); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotateMatrixRadians(radians); - Assert.Equal(b1.BuildMatrix(), b2.BuildMatrix()); - } + protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslationMatrix(translate); + protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScaleMatrix(scale); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotateMatrixRadians(radians); - [Fact] - public void BuilderCanClear() + protected override Vector2 Execute( + AffineTransformBuilder builder, + Rectangle rectangle, + Vector2 sourcePoint) { - var rectangle = new Rectangle(0, 0, 3, 3); - var builder = new AffineTransformBuilder(rectangle); - Matrix3x2 matrix = Matrix3x2.Identity; - matrix.M31 = (float)Math.PI; - - Assert.Equal(Matrix3x2.Identity, builder.BuildMatrix()); - - builder.AppendMatrix(matrix); - Assert.NotEqual(Matrix3x2.Identity, builder.BuildMatrix()); - - builder.Clear(); - Assert.Equal(Matrix3x2.Identity, builder.BuildMatrix()); + Matrix3x2 matrix = builder.BuildMatrix(); + return Vector2.Transform(sourcePoint, matrix); } } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs new file mode 100644 index 0000000000..d109387cc4 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -0,0 +1,151 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; + +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Transforms +{ + public abstract class TransformBuilderTestBase + { + private static readonly ApproximateFloatComparer Comparer = new ApproximateFloatComparer(1e-6f); + + public static readonly TheoryData ScaleTranslate_Data = + new TheoryData + { + // scale, translate, source, expectedDest + + { Vector2.One, Vector2.Zero, Vector2.Zero, Vector2.Zero }, + { Vector2.One, Vector2.Zero, new Vector2(10, 20), new Vector2(10, 20) }, + { Vector2.One, new Vector2(3, 1), new Vector2(10, 20), new Vector2(13, 21) }, + { new Vector2(2, 0.5f), new Vector2(3, 1), new Vector2(10, 20), new Vector2(23, 11) }, + }; + + [Theory] + [MemberData(nameof(ScaleTranslate_Data))] + public void _1Scale_2Translate(Vector2 scale, Vector2 translate, Vector2 source, Vector2 expectedDest) + { + // These operations should be size-agnostic: + var size = new Size(123, 321); + TBuilder builder = this.CreateBuilder(size); + + this.AppendScale(builder, new SizeF(scale)); + this.AppendTranslation(builder, translate); + + Vector2 actualDest = this.Execute(builder, new Rectangle(Point.Empty, size), source); + Assert.True(Comparer.Equals(expectedDest, actualDest)); + } + + public static readonly TheoryData TranslateScale_Data = + new TheoryData + { + // translate, scale, source, expectedDest + + { Vector2.Zero, Vector2.One, Vector2.Zero, Vector2.Zero }, + { Vector2.Zero, Vector2.One, new Vector2(10, 20), new Vector2(10, 20) }, + { new Vector2(3, 1), new Vector2(2, 0.5f), new Vector2(10, 20), new Vector2(26, 10.5f) }, + }; + + [Theory] + [MemberData(nameof(TranslateScale_Data))] + public void _1Translate_2Scale(Vector2 translate, Vector2 scale, Vector2 source, Vector2 expectedDest) + { + // Translate ans scale are size-agnostic: + var size = new Size(456, 432); + TBuilder builder = this.CreateBuilder(size); + + this.AppendTranslation(builder, translate); + this.AppendScale(builder, new SizeF(scale)); + + Vector2 actualDest = this.Execute(builder, new Rectangle(Point.Empty, size), source); + Assert.Equal(expectedDest, actualDest, Comparer); + } + + [Theory] + [InlineData(10, 20)] + [InlineData(-20, 10)] + public void LocationOffsetIsPrepended(int locationX, int locationY) + { + var rectangle = new Rectangle(locationX, locationY, 10, 10); + TBuilder builder = this.CreateBuilder(rectangle); + + this.AppendScale(builder, new SizeF(2, 2)); + + Vector2 actual = this.Execute(builder, rectangle, Vector2.One); + Vector2 expected = new Vector2(-locationX + 1, -locationY + 1) * 2; + + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 42, 84)] + [InlineData(200, 100, 100, 42, 84)] + [InlineData(100, 200, -10, 42, 84)] + public void RotateDegrees_ShouldCreateCenteredMatrix(int width, int height, float deg, float x, float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + this.AppendRotationDegrees(builder, deg); + + // TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness + Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(deg, size); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + + Assert.Equal(actual, expected, Comparer); + } + + [Fact] + public void AppendPrependOpposite() + { + var rectangle = new Rectangle(-1, -1, 3, 3); + TBuilder b1 = this.CreateBuilder(rectangle); + TBuilder b2 = this.CreateBuilder(rectangle); + + const float pi = (float)Math.PI; + + // Forwards + this.AppendRotationRadians(b1, pi); + this.AppendScale(b1, new SizeF(2, 0.5f)); + this.AppendTranslation(b1, new PointF(123, 321)); + + // Backwards + this.PrependTranslation(b2, new PointF(123, 321)); + this.PrependScale(b2, new SizeF(2, 0.5f)); + this.PrependRotationRadians(b2, pi); + + Vector2 p1 = this.Execute(b1, rectangle, new Vector2(32, 65)); + Vector2 p2 = this.Execute(b2, rectangle, new Vector2(32, 65)); + + Assert.Equal(p1, p2, Comparer); + } + + protected TBuilder CreateBuilder(Size size) => this.CreateBuilder(new Rectangle(Point.Empty, size)); + + protected virtual TBuilder CreateBuilder(Rectangle rectangle) => (TBuilder)Activator.CreateInstance(typeof(TBuilder), rectangle); + + protected abstract void AppendTranslation(TBuilder builder, PointF translate); + protected abstract void AppendScale(TBuilder builder, SizeF scale); + protected abstract void AppendRotationRadians(TBuilder builder, float radians); + + protected abstract void PrependTranslation(TBuilder builder, PointF translate); + protected abstract void PrependScale(TBuilder builder, SizeF scale); + protected abstract void PrependRotationRadians(TBuilder builder, float radians); + + protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => + this.AppendRotationRadians(builder, ImageMaths.ToRadian(degrees)); + + protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); + + private static float Sqrt(float a) => (float)Math.Sqrt(a); + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs index 854e57d8f5..47ca6cccb2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -11,7 +11,8 @@ namespace SixLabors.ImageSharp.Tests /// internal readonly struct ApproximateFloatComparer : IEqualityComparer, - IEqualityComparer + IEqualityComparer, + IEqualityComparer { private readonly float Epsilon; @@ -33,9 +34,17 @@ namespace SixLabors.ImageSharp.Tests public int GetHashCode(float obj) => obj.GetHashCode(); /// - public bool Equals(Vector4 x, Vector4 y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z) && this.Equals(x.W, y.W); + public bool Equals(Vector4 a, Vector4 b) => this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y) && this.Equals(a.Z, b.Z) && this.Equals(a.W, b.W); /// public int GetHashCode(Vector4 obj) => obj.GetHashCode(); + + /// + public bool Equals(Vector2 a, Vector2 b) => this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y); + + public int GetHashCode(Vector2 obj) + { + throw new System.NotImplementedException(); + } } } \ No newline at end of file From cc2589f88e7887127b19303a19ad5ae0974cb013 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 23:07:50 +0100 Subject: [PATCH 202/238] rename methods + extend API --- .../Processing/AffineTransformBuilder.cs | 78 +++++++++++++++---- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 6 +- .../Transforms/AffineTransformBuilderTests.cs | 12 +-- .../Transforms/AffineTransformTests.cs | 20 ++--- 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 4d798f4396..1620b72234 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder PrependRotateMatrixDegrees(float degrees) + public AffineTransformBuilder PrependRotationDegrees(float degrees) => this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); /// @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder PrependRotateMatrixRadians(float radians) + public AffineTransformBuilder PrependRotationRadians(float radians) => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); /// @@ -63,32 +63,64 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendRotateMatrixDegrees(float degrees) - => this.AppendRotateMatrixRadians(ImageMaths.ToRadian(degrees)); + public AffineTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(ImageMaths.ToRadian(degrees)); /// /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder AppendRotateMatrixRadians(float radians) + public AffineTransformBuilder AppendRotationRadians(float radians) => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + /// + /// Prepends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public AffineTransformBuilder PrependScale(float scale) + => this.PrependMatrix(Matrix3x2.CreateScale(scale)); + + /// + /// Appends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public AffineTransformBuilder AppendScale(float scale) + => this.AppendMatrix(Matrix3x2.CreateScale(scale)); + /// /// Prepends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder PrependScaleMatrix(SizeF scales) - => this.PrependMatrix(Matrix3x2Extensions.CreateScale(scales)); + public AffineTransformBuilder PrependScale(Vector2 scales) + => this.PrependMatrix(Matrix3x2.CreateScale(scales)); /// /// Appends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder AppendScaleMatrix(SizeF scales) - => this.AppendMatrix(Matrix3x2Extensions.CreateScale(scales)); + public AffineTransformBuilder AppendScale(Vector2 scales) + => this.AppendMatrix(Matrix3x2.CreateScale(scales)); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); /// /// Prepends a centered skew matrix from the give angles in degrees. @@ -96,7 +128,7 @@ namespace SixLabors.ImageSharp.Processing /// The X angle, in degrees. /// The Y angle, in degrees. /// The . - public AffineTransformBuilder PrependSkewMatrixDegrees(float degreesX, float degreesY) + public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) => this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); /// @@ -105,7 +137,7 @@ namespace SixLabors.ImageSharp.Processing /// The X angle, in degrees. /// The Y angle, in degrees. /// The . - public AffineTransformBuilder AppendSkewMatrixDegrees(float degreesX, float degreesY) + public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) => this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); /// @@ -113,16 +145,32 @@ namespace SixLabors.ImageSharp.Processing /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslationMatrix(PointF position) - => this.PrependMatrix(Matrix3x2Extensions.CreateTranslation(position)); + public AffineTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); /// /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslationMatrix(PointF position) - => this.AppendMatrix(Matrix3x2Extensions.CreateTranslation(position)); + public AffineTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); /// /// Prepends a raw matrix. diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 564318e5e3..a29342ad46 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -74,9 +74,9 @@ namespace SixLabors.ImageSharp.Tests using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { AffineTransformBuilder builder = new AffineTransformBuilder(blend.Size()) - .AppendRotateMatrixDegrees(45F) - .AppendScaleMatrix(new SizeF(.25F, .25F)) - .AppendTranslationMatrix(new PointF(10, 10)); + .AppendRotationDegrees(45F) + .AppendScale(new SizeF(.25F, .25F)) + .AppendTranslation(new PointF(10, 10)); // Apply a background color so we can see the translation. blend.Mutate(x => x.Transform(builder).BackgroundColor(NamedColors.HotPink)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 1b4caee14f..639f4b46fa 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -36,13 +36,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms }); } - protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslationMatrix(translate); - protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScaleMatrix(scale); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotateMatrixRadians(radians); + protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); - protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslationMatrix(translate); - protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScaleMatrix(scale); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotateMatrixRadians(radians); + protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); protected override Vector2 Execute( AffineTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 3d7fba2c19..e78bb2c6d9 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees(30); + .AppendRotationDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); @@ -102,9 +102,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { image.DebugSave(provider, $"_original"); AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees(angleDeg) - .AppendScaleMatrix(new SizeF(sx, sy)) - .AppendTranslationMatrix(new PointF(tx, ty)); + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(sx, sy)) + .AppendTranslation(new PointF(tx, ty)); this.PrintMatrix(builder.BuildMatrix()); @@ -124,8 +124,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees(angleDeg) - .AppendScaleMatrix(new SizeF(s, s)); + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(s, s)); image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { image.DebugSave(provider, $"_original"); AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) - .AppendScaleMatrix(new SizeF(2, 1.5F)); + .AppendScale(new SizeF(2, 1.5F)); image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); @@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) - .AppendScaleMatrix(new SizeF(1F, 2F)); + .AppendScale(new SizeF(1F, 2F)); image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); @@ -197,8 +197,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotateMatrixDegrees(50) - .AppendScaleMatrix(new SizeF(.6F, .6F)); + .AppendRotationDegrees(50) + .AppendScale(new SizeF(.6F, .6F)); image.Mutate(i => i.Transform(builder, sampler)); From 0774d5e794d41eb342b05af7ceb65df1c8258681 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 23:18:17 +0100 Subject: [PATCH 203/238] Translation, Scale -> ProjectiveTransformBuilder --- .../Processing/AffineTransformBuilder.cs | 26 ++-- .../Processing/ProjectiveTransformBuilder.cs | 113 ++++++++++++++++-- .../ProjectiveTransformBuilderTests.cs | 54 +++------ 3 files changed, 131 insertions(+), 62 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 1620b72234..cd66272b42 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing public class AffineTransformBuilder { private readonly List matrices = new List(); - private readonly Rectangle rectangle; + private readonly Rectangle sourceRectangle; /// /// Initializes a new instance of the class. @@ -34,13 +34,13 @@ namespace SixLabors.ImageSharp.Processing Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); - this.rectangle = sourceRectangle; + this.sourceRectangle = sourceRectangle; } /// /// Gets the source image size. /// - internal Size Size => this.rectangle.Size; + internal Size Size => this.sourceRectangle.Size; /// /// Prepends a centered rotation matrix using the given rotation in degrees. @@ -145,32 +145,32 @@ namespace SixLabors.ImageSharp.Processing /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslation(PointF position) - => this.PrependTranslation((Vector2)position); + public AffineTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); /// /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslation(PointF position) - => this.AppendTranslation((Vector2)position); + public AffineTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); /// /// Prepends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslation(Vector2 position) - => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); + public AffineTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); /// /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslation(Vector2 position) - => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); + public AffineTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); /// /// Prepends a raw matrix. @@ -203,9 +203,9 @@ namespace SixLabors.ImageSharp.Processing Matrix3x2 matrix = Matrix3x2.Identity; // Translate the origin matrix to cater for source rectangle offsets. - if (!this.rectangle.Equals(default)) + if (!this.sourceRectangle.Equals(default)) { - matrix *= Matrix3x2.CreateTranslation(-this.rectangle.Location); + matrix *= Matrix3x2.CreateTranslation(-this.sourceRectangle.Location); } foreach (Matrix3x2 m in this.matrices) diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index be4c675189..6c5fb46259 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -14,18 +14,15 @@ namespace SixLabors.ImageSharp.Processing public class ProjectiveTransformBuilder { private readonly List matrices = new List(); - private Rectangle rectangle; + private Rectangle sourceRectangle; /// /// Initializes a new instance of the class. /// /// The source image size. public ProjectiveTransformBuilder(Size sourceSize) + : this(new Rectangle(Point.Empty, sourceSize)) { - Guard.MustBeGreaterThan(sourceSize.Width, 0, nameof(sourceSize)); - Guard.MustBeGreaterThan(sourceSize.Height, 0, nameof(sourceSize)); - - this.Size = sourceSize; } /// @@ -33,13 +30,18 @@ namespace SixLabors.ImageSharp.Processing /// /// The source rectangle. public ProjectiveTransformBuilder(Rectangle sourceRectangle) - : this(sourceRectangle.Size) - => this.rectangle = sourceRectangle; + { + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); + + this.sourceRectangle = sourceRectangle; + } /// /// Gets the source image size. /// - internal Size Size { get; } + internal Size Size => this.sourceRectangle.Size; + /// /// Prepends a matrix that performs a tapering projective transform. @@ -61,6 +63,96 @@ namespace SixLabors.ImageSharp.Processing public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + public void AppendRotationRadians(float radians) + { + throw new System.NotImplementedException(); + } + + public void PrependRotationRadians(float radians) + { + throw new System.NotImplementedException(); + } + + /// + /// Prepends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public ProjectiveTransformBuilder PrependScale(float scale) + => this.PrependMatrix(Matrix4x4.CreateScale(scale)); + + /// + /// Appends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public ProjectiveTransformBuilder AppendScale(float scale) + => this.AppendMatrix(Matrix4x4.CreateScale(scale)); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(Vector2 scales) + => this.PrependMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f))); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder AppendScale(Vector2 scales) + => this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f))); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); + /// /// Prepends a raw matrix. /// @@ -92,9 +184,9 @@ namespace SixLabors.ImageSharp.Processing Matrix4x4 matrix = Matrix4x4.Identity; // Translate the origin matrix to cater for source rectangle offsets. - if (!this.rectangle.Equals(default)) + if (!this.sourceRectangle.Equals(default)) { - matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.rectangle.Location, 0)); + matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.sourceRectangle.Location, 0)); } foreach (Matrix4x4 m in this.matrices) @@ -109,5 +201,6 @@ namespace SixLabors.ImageSharp.Processing /// Removes all matrices from the builder. /// public void Clear() => this.matrices.Clear(); + } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 3dfc42d4f7..0d9bd301dc 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -9,7 +9,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Transforms { - public class ProjectiveTransformBuilderTests + public class ProjectiveTransformBuilderTests : TransformBuilderTestBase { [Fact] public void ConstructorAssignsProperties() @@ -34,45 +34,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); }); } - - [Fact] - public void AppendPrependOpposite() - { - var rectangle = new Rectangle(-1, -1, 3, 3); - var b1 = new ProjectiveTransformBuilder(rectangle); - var b2 = new ProjectiveTransformBuilder(rectangle); - - const float pi = (float)Math.PI; - - Matrix4x4 m4 = Matrix4x4.Identity; - m4.M31 = pi; - - // Forwards - b1.AppendMatrix(m4) - .AppendTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi); - - // Backwards - b2.PrependTaperMatrix(TaperSide.Left, TaperCorner.LeftOrTop, pi) - .PrependMatrix(m4); - - Assert.Equal(b1.BuildMatrix(), b2.BuildMatrix()); - } - - [Fact] - public void BuilderCanClear() + protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + + protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + + protected override Vector2 Execute( + ProjectiveTransformBuilder builder, + Rectangle rectangle, + Vector2 sourcePoint) { - var rectangle = new Rectangle(0, 0, 3, 3); - var builder = new ProjectiveTransformBuilder(rectangle); - Matrix4x4 matrix = Matrix4x4.Identity; - matrix.M31 = (float)Math.PI; - - Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix()); - - builder.AppendMatrix(matrix); - Assert.NotEqual(Matrix4x4.Identity, builder.BuildMatrix()); - - builder.Clear(); - Assert.Equal(Matrix4x4.Identity, builder.BuildMatrix()); + Matrix4x4 matrix = builder.BuildMatrix(); + return Vector2.Transform(sourcePoint, matrix); } } } From e5f7b12c7ee165b2996cfe3d704c9ce6ac2e6e2d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 23:29:34 +0100 Subject: [PATCH 204/238] extend ProjectiveTransformBuilder --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- .../Processing/AffineTransformBuilder.cs | 29 +++++++------- .../Processing/ProjectiveTransformBuilder.cs | 38 ++++++++++++++++--- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 2 +- .../Transforms/AffineTransformBuilderTests.cs | 4 +- .../Transforms/AffineTransformTests.cs | 8 ++-- .../ProjectiveTransformBuilderTests.cs | 5 ++- .../Transforms/TransformBuilderTestBase.cs | 2 +- 8 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 45556741e6..c0c8e07e6f 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp /// Converts degrees to radians /// [MethodImpl(InliningOptions.ShortMethod)] - public static float ToRadian(float degrees) + public static float DegreesToRadians(float degrees) { return degrees * ((float)Math.PI / 180f); } diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index cd66272b42..1f26d079d4 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -42,37 +42,38 @@ namespace SixLabors.ImageSharp.Processing /// internal Size Size => this.sourceRectangle.Size; + /// - /// Prepends a centered rotation matrix using the given rotation in degrees. + /// Prepends a centered rotation matrix using the given rotation in radians. /// - /// The amount of rotation, in degrees. + /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder PrependRotationDegrees(float degrees) - => this.PrependMatrix(TransformUtils.CreateRotationMatrixDegrees(degrees, this.Size)); + public AffineTransformBuilder PrependCenteredRotationRadians(float radians) + => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); /// - /// Prepends a centered rotation matrix using the given rotation in radians. + /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder PrependRotationRadians(float radians) - => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + public AffineTransformBuilder AppendCenteredRotationRadians(float radians) + => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); /// - /// Appends a centered rotation matrix using the given rotation in degrees. + /// Prepends a centered rotation matrix using the given rotation in degrees. /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(ImageMaths.ToRadian(degrees)); + public AffineTransformBuilder PrependCenteredRotationDegrees(float degrees) + => this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Appends a centered rotation matrix using the given rotation in degrees. /// - /// The amount of rotation, in radians. + /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendRotationRadians(float radians) - => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + public AffineTransformBuilder AppendCenteredRotationDegrees(float degrees) + => this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 6c5fb46259..58c02108ac 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); this.sourceRectangle = sourceRectangle; - } + } /// /// Gets the source image size. @@ -63,16 +63,44 @@ namespace SixLabors.ImageSharp.Processing public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); - public void AppendRotationRadians(float radians) + /// + /// Prepends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public ProjectiveTransformBuilder PrependCenteredRotationRadians(float radians) { - throw new System.NotImplementedException(); + var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + return this.PrependMatrix(m); } - public void PrependRotationRadians(float radians) + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public ProjectiveTransformBuilder AppendCenteredRotationRadians(float radians) { - throw new System.NotImplementedException(); + var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + return this.AppendMatrix(m); } + /// + /// Prepends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) + => this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + + /// + /// Appends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder AppendCenteredRotationDegrees(float degrees) + => this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + /// /// Prepends a scale matrix from the given uniform scale. /// diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index a29342ad46..2f89236544 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { AffineTransformBuilder builder = new AffineTransformBuilder(blend.Size()) - .AppendRotationDegrees(45F) + .AppendCenteredRotationDegrees(45F) .AppendScale(new SizeF(.25F, .25F)) .AppendTranslation(new PointF(10, 10)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 639f4b46fa..2a43e56e70 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -38,11 +38,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); protected override Vector2 Execute( AffineTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index e78bb2c6d9..f86db5641f 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotationDegrees(30); + .AppendCenteredRotationDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { image.DebugSave(provider, $"_original"); AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotationDegrees(angleDeg) + .AppendCenteredRotationDegrees(angleDeg) .AppendScale(new SizeF(sx, sy)) .AppendTranslation(new PointF(tx, ty)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotationDegrees(angleDeg) + .AppendCenteredRotationDegrees(angleDeg) .AppendScale(new SizeF(s, s)); image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) - .AppendRotationDegrees(50) + .AppendCenteredRotationDegrees(50) .AppendScale(new SizeF(.6F, .6F)); image.Mutate(i => i.Transform(builder, sampler)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 0d9bd301dc..f467bed40c 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -34,13 +34,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); }); } + protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); - protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); protected override Vector2 Execute( ProjectiveTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index d109387cc4..3f259c9aa2 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void PrependRotationRadians(TBuilder builder, float radians); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => - this.AppendRotationRadians(builder, ImageMaths.ToRadian(degrees)); + this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees)); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); From 59f47d457b1c72d8ae2baa49fdf351932f7bb9fd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 25 Nov 2018 23:31:05 +0100 Subject: [PATCH 205/238] fix trailing whitespace warnings --- src/ImageSharp/Processing/AffineTransformBuilder.cs | 1 - src/ImageSharp/Processing/ProjectiveTransformBuilder.cs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 1f26d079d4..a1305d1212 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -42,7 +42,6 @@ namespace SixLabors.ImageSharp.Processing /// internal Size Size => this.sourceRectangle.Size; - /// /// Prepends a centered rotation matrix using the given rotation in radians. /// diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 58c02108ac..9bcbaf8343 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -42,7 +42,6 @@ namespace SixLabors.ImageSharp.Processing /// internal Size Size => this.sourceRectangle.Size; - /// /// Prepends a matrix that performs a tapering projective transform. /// @@ -229,6 +228,5 @@ namespace SixLabors.ImageSharp.Processing /// Removes all matrices from the builder. /// public void Clear() => this.matrices.Clear(); - } } \ No newline at end of file From 103d12901234874c91131faeedc1123088830581 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 01:09:47 +0100 Subject: [PATCH 206/238] Make AffineTransformProcessor and AffineTransformBuilder API more flexible --- .../Processing/AffineTransformBuilder.cs | 83 ++++++++----------- .../Transforms/AffineTransformProcessor.cs | 6 +- .../Processing/TransformExtensions.cs | 71 ++++++++++++++-- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 2 +- .../Transforms/AffineTransformBuilderTests.cs | 28 +------ .../Transforms/AffineTransformTests.cs | 18 ++-- .../ProjectiveTransformBuilderTests.cs | 2 + .../Transforms/TransformBuilderTestBase.cs | 18 +++- 8 files changed, 136 insertions(+), 92 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index a1305d1212..42d555f203 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; using System.Numerics; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -13,34 +14,7 @@ namespace SixLabors.ImageSharp.Processing /// public class AffineTransformBuilder { - private readonly List matrices = new List(); - private readonly Rectangle sourceRectangle; - - /// - /// Initializes a new instance of the class. - /// - /// The source image size. - public AffineTransformBuilder(Size sourceSize) - : this(new Rectangle(Point.Empty, sourceSize)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The source rectangle. - public AffineTransformBuilder(Rectangle sourceRectangle) - { - Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); - Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); - - this.sourceRectangle = sourceRectangle; - } - - /// - /// Gets the source image size. - /// - internal Size Size => this.sourceRectangle.Size; + private readonly List> matrixFactories = new List>(); /// /// Prepends a centered rotation matrix using the given rotation in radians. @@ -48,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in radians. /// The . public AffineTransformBuilder PrependCenteredRotationRadians(float radians) - => this.PrependMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// /// Appends a centered rotation matrix using the given rotation in radians. @@ -56,7 +30,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in radians. /// The . public AffineTransformBuilder AppendCenteredRotationRadians(float radians) - => this.AppendMatrix(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); + => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// /// Prepends a centered rotation matrix using the given rotation in degrees. @@ -129,7 +103,7 @@ namespace SixLabors.ImageSharp.Processing /// The Y angle, in degrees. /// The . public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) - => this.PrependMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + => this.Prepend(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); /// /// Appends a centered skew matrix from the give angles in degrees. @@ -138,7 +112,7 @@ namespace SixLabors.ImageSharp.Processing /// The Y angle, in degrees. /// The . public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) - => this.AppendMatrix(TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, this.Size)); + => this.Append(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); /// /// Prepends a translation matrix from the given vector. @@ -179,7 +153,7 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) { - this.matrices.Insert(0, matrix); + this.matrixFactories.Insert(0, _ => matrix); return this; } @@ -190,35 +164,50 @@ namespace SixLabors.ImageSharp.Processing /// The . public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) { - this.matrices.Add(matrix); + this.matrixFactories.Add(_ => matrix); return this; } /// - /// Returns the combined matrix. + /// Returns the combined matrix for a given source size. + /// + /// The source image size + /// The . + public Matrix3x2 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); + + /// + /// Returns the combined matrix for a given source rectangle. /// + /// The rectangle in the source image /// The . - public Matrix3x2 BuildMatrix() + public Matrix3x2 BuildMatrix(Rectangle sourceRectangle) { - Matrix3x2 matrix = Matrix3x2.Identity; + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); // Translate the origin matrix to cater for source rectangle offsets. - if (!this.sourceRectangle.Equals(default)) - { - matrix *= Matrix3x2.CreateTranslation(-this.sourceRectangle.Location); - } + var matrix = Matrix3x2.CreateTranslation(-sourceRectangle.Location); - foreach (Matrix3x2 m in this.matrices) + Size size = sourceRectangle.Size; + + foreach (Func factory in this.matrixFactories) { - matrix *= m; + matrix *= factory(size); } return matrix; } - /// - /// Removes all matrices from the builder. - /// - public void Clear() => this.matrices.Clear(); + private AffineTransformBuilder Prepend(Func factory) + { + this.matrixFactories.Insert(0, factory); + return this; + } + + private AffineTransformBuilder Append(Func factory) + { + this.matrixFactories.Add(factory); + return this; + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 2370adb862..f357b6c277 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -24,13 +24,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The transform matrix. /// The sampler to perform the transform operation. - /// The source image size. - public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize) + /// The target dimensions. + public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size targetDimensions) { Guard.NotNull(sampler, nameof(sampler)); this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = TransformUtils.GetTransformedSize(sourceSize, matrix); + this.TargetDimensions = targetDimensions;; } /// diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index ea789eb3d7..de4a3e5ba7 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -1,8 +1,11 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Numerics; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing { @@ -11,6 +14,29 @@ namespace SixLabors.ImageSharp.Processing /// public static class TransformExtensions { + /// + /// Performs an affine transform of an image using the specified sampling algorithm. + /// + /// The pixel format. + /// The . + /// The source rectangle + /// The transformation matrix. + /// The size of the result image. + /// The to perform the resampling. + /// The + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + Matrix3x2 transform, + Size targetDimensions, + IResampler sampler) + where TPixel : struct, IPixel + { + return ctx.ApplyProcessor( + new AffineTransformProcessor(transform, sampler, targetDimensions), + sourceRectangle); + } + /// /// Performs an affine transform of an image. /// @@ -18,7 +44,9 @@ namespace SixLabors.ImageSharp.Processing /// The image to transform. /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, AffineTransformBuilder builder) + public static IImageProcessingContext Transform( + this IImageProcessingContext source, + AffineTransformBuilder builder) where TPixel : struct, IPixel => Transform(source, builder, KnownResamplers.Bicubic); @@ -26,13 +54,39 @@ namespace SixLabors.ImageSharp.Processing /// Performs an affine transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. + /// The . + /// The source rectangle + /// The affine transform builder. + /// The to perform the resampling. + /// The + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + AffineTransformBuilder builder, + IResampler sampler) + where TPixel : struct, IPixel + { + Matrix3x2 transform = builder.BuildMatrix(sourceRectangle); + Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform); + return ctx.Transform(sourceRectangle, transform, targetDimensions, sampler); + } + + /// + /// Performs an affine transform of an image using the specified sampling algorithm. + /// + /// The pixel format. + /// The . /// The affine transform builder. /// The to perform the resampling. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, AffineTransformBuilder builder, IResampler sampler) + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + AffineTransformBuilder builder, + IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); + { + return ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); + } /// /// Performs a projective transform of an image. @@ -41,7 +95,9 @@ namespace SixLabors.ImageSharp.Processing /// The image to transform. /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, ProjectiveTransformBuilder builder) + public static IImageProcessingContext Transform( + this IImageProcessingContext source, + ProjectiveTransformBuilder builder) where TPixel : struct, IPixel => Transform(source, builder, KnownResamplers.Bicubic); @@ -53,7 +109,10 @@ namespace SixLabors.ImageSharp.Processing /// The projective transform builder. /// The to perform the resampling. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, ProjectiveTransformBuilder builder, IResampler sampler) + public static IImageProcessingContext Transform( + this IImageProcessingContext source, + ProjectiveTransformBuilder builder, + IResampler sampler) where TPixel : struct, IPixel => source.ApplyProcessor(new ProjectiveTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); } diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 2f89236544..f3772e3aa3 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests using (Image image = provider.GetImage()) using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { - AffineTransformBuilder builder = new AffineTransformBuilder(blend.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(45F) .AppendScale(new SizeF(.25F, .25F)) .AppendTranslation(new PointF(10, 10)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 2a43e56e70..cbbf59caf5 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -12,30 +12,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class AffineTransformBuilderTests : TransformBuilderTestBase { - [Fact] - public void ConstructorAssignsProperties() - { - var s = new Size(1, 1); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - Assert.Equal(s, builder.Size); - } - - [Fact] - public void ConstructorThrowsInvalid() - { - Assert.Throws(() => - { - var s = new Size(0, 1); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - }); - - Assert.Throws(() => - { - var s = new Size(1, 0); - var builder = new AffineTransformBuilder(new Rectangle(Point.Empty, s)); - }); - } - protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); @@ -44,12 +20,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); + protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); + protected override Vector2 Execute( AffineTransformBuilder builder, Rectangle rectangle, Vector2 sourcePoint) { - Matrix3x2 matrix = builder.BuildMatrix(); + Matrix3x2 matrix = builder.BuildMatrix(rectangle); return Vector2.Transform(sourcePoint, matrix); } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index f86db5641f..0c167d7f97 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler resampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); @@ -101,12 +101,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { image.DebugSave(provider, $"_original"); - AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(angleDeg) .AppendScale(new SizeF(sx, sy)) .AppendTranslation(new PointF(tx, ty)); - this.PrintMatrix(builder.BuildMatrix()); + this.PrintMatrix(builder.BuildMatrix(image.Size())); image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(angleDeg) .AppendScale(new SizeF(s, s)); @@ -159,10 +159,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { image.DebugSave(provider, $"_original"); - AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendScale(new SizeF(2, 1.5F)); - image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -178,10 +178,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { - AffineTransformBuilder builder = new AffineTransformBuilder(rectangle) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendScale(new SizeF(1F, 2F)); - image.Mutate(i => i.Transform(builder, KnownResamplers.Spline)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -196,7 +196,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - AffineTransformBuilder builder = new AffineTransformBuilder(image.Size()) + AffineTransformBuilder builder = new AffineTransformBuilder() .AppendCenteredRotationDegrees(50) .AppendScale(new SizeF(.6F, .6F)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index f467bed40c..14ed57033e 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -35,6 +35,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms }); } + protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(rectangle); + protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 3f259c9aa2..648ed5861f 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -129,9 +129,25 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(p1, p2, Comparer); } + [Theory] + [InlineData(0, 1)] + [InlineData(1, 0)] + [InlineData(-1, 0)] + public void ThrowsForInvalidSizes(int width, int height) + { + var size = new Size(width, height); + + Assert.ThrowsAny( + () => + { + TBuilder builder = this.CreateBuilder(size); + this.Execute(builder, new Rectangle(Point.Empty, size), Vector2.Zero); + }); + } + protected TBuilder CreateBuilder(Size size) => this.CreateBuilder(new Rectangle(Point.Empty, size)); - protected virtual TBuilder CreateBuilder(Rectangle rectangle) => (TBuilder)Activator.CreateInstance(typeof(TBuilder), rectangle); + protected abstract TBuilder CreateBuilder(Rectangle rectangle); protected abstract void AppendTranslation(TBuilder builder, PointF translate); protected abstract void AppendScale(TBuilder builder, SizeF scale); From eab8a5677c73074f68cb369814a27beaf2e57641 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 01:19:53 +0100 Subject: [PATCH 207/238] fix rotate and skew processors --- .../Processors/Transforms/RotateProcessor.cs | 10 +++++++++- .../Processing/Processors/Transforms/SkewProcessor.cs | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 57cca4bf9e..69ecf59215 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Numerics; + using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.ParallelUtils; @@ -34,12 +36,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the rotating operation. /// The source image size public RotateProcessor(float degrees, IResampler sampler, Size sourceSize) - : base( + : this( TransformUtils.CreateRotationMatrixDegrees(degrees, sourceSize), sampler, sourceSize) => this.Degrees = degrees; + // Helper constructor + private RotateProcessor(Matrix3x2 rotationMatrix, IResampler sampler, Size sourceSize) + : base(rotationMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, rotationMatrix)) + { + } + /// /// Gets the angle of rotation in degrees. /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs index 4a006a9dfe..c7b1d74104 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Numerics; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -32,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the skew operation. /// The source image size public SkewProcessor(float degreesX, float degreesY, IResampler sampler, Size sourceSize) - : base( + : this( TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, sourceSize), sampler, sourceSize) @@ -41,6 +43,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.DegreesY = degreesY; } + // Helper constructor: + private SkewProcessor(Matrix3x2 skewMatrix, IResampler sampler, Size sourceSize) + : base(skewMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, skewMatrix)) + { + } + /// /// Gets the angle of rotation along the x-axis in degrees. /// From 81e16e48a3141ecd1e5fdfd62ab07cc6449600bb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 01:29:31 +0100 Subject: [PATCH 208/238] StyleCop --- .../Processors/Transforms/AffineTransformProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index f357b6c277..aabaa63cf9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Guard.NotNull(sampler, nameof(sampler)); this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = targetDimensions;; + this.TargetDimensions = targetDimensions; } /// From bbfb2a0ef9249183bce9f8128d4ad058361a8ef2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 02:37:10 +0100 Subject: [PATCH 209/238] Rotation around custom center point. Rename PrependCenteredRotationRadians back to PrependRotationRadians --- .../Processing/AffineTransformBuilder.cs | 40 ++++++++++++---- .../Processing/ProjectiveTransformBuilder.cs | 35 ++++++++++++-- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 2 +- .../Transforms/AffineTransformBuilderTests.cs | 8 +++- .../Transforms/AffineTransformTests.cs | 8 ++-- .../ProjectiveTransformBuilderTests.cs | 8 +++- .../Transforms/TransformBuilderTestBase.cs | 46 +++++++++++++++++-- 7 files changed, 121 insertions(+), 26 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 42d555f203..eab75cfdbe 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -20,33 +20,55 @@ namespace SixLabors.ImageSharp.Processing /// Prepends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. + /// The rotation center point /// The . - public AffineTransformBuilder PrependCenteredRotationRadians(float radians) - => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + public AffineTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) + => this.PrependMatrix(Matrix3x2.CreateRotation(radians, centerPoint)); /// /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. + /// The rotation center point + /// The . + public AffineTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) + => this.AppendMatrix(Matrix3x2.CreateRotation(radians, centerPoint)); + + /// + /// Prepends a rotation matrix using the given rotation angle in radians + /// and the image center point as rotation center. + /// + /// The amount of rotation, in radians. + /// The . + public AffineTransformBuilder PrependRotationRadians(float radians) + => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + + /// + /// Appends a rotation matrix using the given rotation angle in radians + /// and the image center point as rotation center. + /// + /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder AppendCenteredRotationRadians(float radians) + public AffineTransformBuilder AppendRotationRadians(float radians) => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// - /// Prepends a centered rotation matrix using the given rotation in degrees. + /// Prepends a rotation matrix using the given rotation angle in degrees + /// and the image center point as rotation center. /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + public AffineTransformBuilder PrependRotationDegrees(float degrees) + => this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// - /// Appends a centered rotation matrix using the given rotation in degrees. + /// Appends a rotation matrix using the given rotation angle in degrees + /// and the image center point as rotation center. /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendCenteredRotationDegrees(float degrees) - => this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + public AffineTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 9bcbaf8343..8bde90d51a 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; using System.Numerics; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -67,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in radians. /// The . - public ProjectiveTransformBuilder PrependCenteredRotationRadians(float radians) + public ProjectiveTransformBuilder PrependRotationRadians(float radians) { var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); return this.PrependMatrix(m); @@ -78,27 +79,51 @@ namespace SixLabors.ImageSharp.Processing /// /// The amount of rotation, in radians. /// The . - public ProjectiveTransformBuilder AppendCenteredRotationRadians(float radians) + public ProjectiveTransformBuilder AppendRotationRadians(float radians) { var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); return this.AppendMatrix(m); } + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The rotation center. + /// The . + internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) + { + var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0)); + return this.PrependMatrix(m); + } + + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The rotation center. + /// The . + internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) + { + var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0)); + return this.AppendMatrix(m); + } + /// /// Prepends a centered rotation matrix using the given rotation in degrees. /// /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// /// Appends a centered rotation matrix using the given rotation in degrees. /// /// The amount of rotation, in degrees. /// The . - public ProjectiveTransformBuilder AppendCenteredRotationDegrees(float degrees) - => this.AppendCenteredRotationRadians(ImageMaths.DegreesToRadians(degrees)); + public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index f3772e3aa3..374454afba 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(45F) + .AppendRotationDegrees(45F) .AppendScale(new SizeF(.25F, .25F)) .AppendTranslation(new PointF(10, 10)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index cbbf59caf5..e025851684 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -14,11 +14,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => + builder.AppendRotationRadians(radians, center); protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => + builder.PrependRotationRadians(radians, center); protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index 0c167d7f97..ed6d3ef2bc 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(30); + .AppendRotationDegrees(30); image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { image.DebugSave(provider, $"_original"); AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(angleDeg) + .AppendRotationDegrees(angleDeg) .AppendScale(new SizeF(sx, sy)) .AppendTranslation(new PointF(tx, ty)); @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(angleDeg) + .AppendRotationDegrees(angleDeg) .AppendScale(new SizeF(s, s)); image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendCenteredRotationDegrees(50) + .AppendRotationDegrees(50) .AppendScale(new SizeF(.6F, .6F)); image.Mutate(i => i.Transform(builder, sampler)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 14ed57033e..01448ac596 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -39,11 +39,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendCenteredRotationRadians(radians); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => + builder.AppendRotationRadians(radians, center); protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); - protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependCenteredRotationRadians(radians); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => + builder.PrependRotationRadians(radians, center); protected override Vector2 Execute( ProjectiveTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 648ed5861f..badf430132 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -87,7 +87,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms [InlineData(200, 100, 10, 42, 84)] [InlineData(200, 100, 100, 42, 84)] [InlineData(100, 200, -10, 42, 84)] - public void RotateDegrees_ShouldCreateCenteredMatrix(int width, int height, float deg, float x, float y) + public void AppendRotationDegrees_WithoutSpecificRotationCenter_RotationIsCenteredAroundImageCenter( + int width, + int height, + float deg, + float x, + float y) { var size = new Size(width, height); TBuilder builder = this.CreateBuilder(size); @@ -97,13 +102,41 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms // TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(deg, size); - var position = new Vector2(x, y); + var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); Assert.Equal(actual, expected, Comparer); } - + + [Theory] + [InlineData(200, 100, 10, 30, 61, 42, 84)] + [InlineData(200, 100, 100, 30, 10, 20, 84)] + [InlineData(100, 200, -10, 30, 20, 11, 84)] + public void AppendRotationDegrees_WithRotationCenter( + int width, + int height, + float deg, + float cx, + float cy, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + var centerPoint = new Vector2(cx, cy); + this.AppendRotationDegrees(builder, deg, centerPoint); + + var matrix = Matrix3x2.CreateRotation(ImageMaths.DegreesToRadians(deg), centerPoint); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + + Assert.Equal(actual, expected, Comparer); + } + [Fact] public void AppendPrependOpposite() { @@ -116,10 +149,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms // Forwards this.AppendRotationRadians(b1, pi); this.AppendScale(b1, new SizeF(2, 0.5f)); + this.AppendRotationRadians(b1, pi / 2, new Vector2(-0.5f, -0.1f)); this.AppendTranslation(b1, new PointF(123, 321)); // Backwards this.PrependTranslation(b2, new PointF(123, 321)); + this.PrependRotationRadians(b2, pi / 2, new Vector2(-0.5f, -0.1f)); this.PrependScale(b2, new SizeF(2, 0.5f)); this.PrependRotationRadians(b2, pi); @@ -152,14 +187,19 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void AppendTranslation(TBuilder builder, PointF translate); protected abstract void AppendScale(TBuilder builder, SizeF scale); protected abstract void AppendRotationRadians(TBuilder builder, float radians); + protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 center); protected abstract void PrependTranslation(TBuilder builder, PointF translate); protected abstract void PrependScale(TBuilder builder, SizeF scale); protected abstract void PrependRotationRadians(TBuilder builder, float radians); + protected abstract void PrependRotationRadians(TBuilder b1, float v, Vector2 vector2); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees)); + protected virtual void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 center) => + this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees), center); + protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); private static float Sqrt(float a) => (float)Math.Sqrt(a); From 0c9d6bbec115cd91448050bf8bc942ffb5c927fc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 16:11:38 +0100 Subject: [PATCH 210/238] printing ReferenceKernelMap --- .../KernelMapTests.ReferenceKernelMap.cs | 9 ++++- .../Processors/Transforms/KernelMapTests.cs | 39 +++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 932ea54948..cf0e94e8b4 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms /// /// Simplified reference implementation for functionality. /// - public class ReferenceKernelMap + internal class ReferenceKernelMap { private readonly ReferenceKernel[] kernels; @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } - public struct ReferenceKernel + internal struct ReferenceKernel { public ReferenceKernel(int left, float[] values) { @@ -94,6 +94,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public float[] Values { get; } public int Length => this.Values.Length; + + public static implicit operator ReferenceKernel(ResizeKernel orig) + { + return new ReferenceKernel(orig.Left, orig.GetValues().ToArray()); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 7abc1c3122..555ed15675 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos3), 8, 6 }, // TODO: What's wrong here: - // { nameof(KnownResamplers.Lanczos3), 20, 12 }, + { nameof(KnownResamplers.Lanczos3), 20, 12 }, {nameof(KnownResamplers.Lanczos8), 500, 200 }, {nameof(KnownResamplers.Lanczos8), 100, 10 }, @@ -61,8 +61,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); #if DEBUG - string text = PrintKernelMap(kernelMap); - this.Output.WriteLine(text); + this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); + this.Output.WriteLine($"Reference KernelMap:\n{PrintKernelMap(referenceMap)}\n"); #endif for (int i = 0; i < kernelMap.DestinationSize; i++) @@ -73,19 +73,42 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms Assert.Equal(referenceKernel.Length, kernel.Length); Assert.Equal(referenceKernel.Left, kernel.Left); - Assert.True(kernel.GetValues().SequenceEqual(referenceKernel.Values)); + float[] expectedValues = referenceKernel.Values; + Span actualValues = kernel.GetValues(); + + Assert.Equal(expectedValues.Length, actualValues.Length); + + var comparer = new ApproximateFloatComparer(1e-6f); + + for (int x = 0; x < expectedValues.Length; x++) + { + Assert.True( + comparer.Equals(expectedValues[x], actualValues[x]), + $"{expectedValues[x]} != {actualValues[x]} @ (Row:{i}, Col:{x})"); + } } } - private static string PrintKernelMap(KernelMap kernelMap) + private static string PrintKernelMap(KernelMap kernelMap) => + PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); + + private static string PrintKernelMap(ReferenceKernelMap kernelMap) => + PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); + + private static string PrintKernelMap( + TKernelMap kernelMap, + Func getDestinationSize, + Func getKernel) { var bld = new StringBuilder(); - for (int i = 0; i < kernelMap.DestinationSize; i++) + int destinationSize = getDestinationSize(kernelMap); + + for (int i = 0; i < destinationSize; i++) { - ResizeKernel kernel = kernelMap.GetKernel(i); + ReferenceKernel kernel = getKernel(kernelMap, i); bld.Append($"({kernel.Left:D3}) || "); - Span span = kernel.GetValues(); + Span span = kernel.Values; for (int j = 0; j < kernel.Length; j++) { From eb82f9af683dc67e5b7d6c63f0d925273a640c38 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 26 Nov 2018 16:48:29 +0100 Subject: [PATCH 211/238] fixed a bug in KernelMap caused by overlapping memory areas --- .../Processors/Transforms/KernelMap.cs | 11 +++++++++-- .../Processors/Transforms/KernelMapTests.cs | 16 +++++++--------- .../Processing/Processors/Transforms/SkewTest.cs | 14 +------------- .../ImageSharp.Tests/TestUtilities/TestUtils.cs | 13 +++++++++++++ 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index 3f984fef0d..3f2bf8dda4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.periodicRegionMin = period + radius; this.periodicRegionMax = destinationSize - radius; - int width = radius * 2; + int width = (radius * 2) + 1; this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); this.kernels = new ResizeKernel[destinationSize]; } @@ -141,8 +141,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// private ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) { - int flatStartIndex = destIdx * this.data.Width; int length = rightIdx - left + 1; + + if (length > this.data.Width) + { + throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width"); + } + + int flatStartIndex = destIdx * this.data.Width; + Memory bufferSlice = this.data.Memory.Slice(flatStartIndex, length); return new ResizeKernel(left, bufferSlice); } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 555ed15675..c5916ce0be 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.PixelFormats; @@ -40,25 +41,22 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos3), 9, 12 }, { nameof(KnownResamplers.Lanczos3), 6, 8 }, { nameof(KnownResamplers.Lanczos3), 8, 6 }, - - // TODO: What's wrong here: { nameof(KnownResamplers.Lanczos3), 20, 12 }, - {nameof(KnownResamplers.Lanczos8), 500, 200 }, - {nameof(KnownResamplers.Lanczos8), 100, 10 }, - {nameof(KnownResamplers.Lanczos8), 100, 80 }, - {nameof(KnownResamplers.Lanczos8), 10, 100 }, + { nameof(KnownResamplers.Lanczos8), 500, 200 }, + { nameof(KnownResamplers.Lanczos8), 100, 10 }, + { nameof(KnownResamplers.Lanczos8), 100, 80 }, + { nameof(KnownResamplers.Lanczos8), 10, 100 }, }; [Theory] [MemberData(nameof(KernelMapData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { - var resampler = (IResampler)typeof(KnownResamplers).GetProperty(resamplerName).GetValue(null); - - var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); + IResampler resampler = TestUtils.GetResampler(resamplerName); var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); + var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs index d1d2ea0771..29c51543fc 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { foreach (string resamplerName in ResamplerNames) { - IResampler sampler = GetResampler(resamplerName); + IResampler sampler = TestUtils.GetResampler(resamplerName); using (Image image = provider.GetImage()) { image.Mutate(i => i.Skew(x, y, sampler)); @@ -68,17 +68,5 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } } - - private static IResampler GetResampler(string name) - { - PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); - - if (property is null) - { - throw new Exception($"No resampler named '{name}"); - } - - return (IResampler)property.GetValue(null); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index d7755ff7a4..5ea0bccf06 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; @@ -284,5 +285,17 @@ namespace SixLabors.ImageSharp.Tests } public static string AsInvariantString(this FormattableString formattable) => System.FormattableString.Invariant(formattable); + + public static IResampler GetResampler(string name) + { + PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); + + if (property is null) + { + throw new Exception($"No resampler named '{name}"); + } + + return (IResampler)property.GetValue(null); + } } } \ No newline at end of file From 5d034d5fc0f51d593a7ae2b7a3b827308d3b9415 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Nov 2018 18:16:47 +0000 Subject: [PATCH 212/238] Use existing method. (There's precedence) --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 14 +------------- .../Processing/AffineTransformBuilder.cs | 4 ++-- .../Processing/ProjectiveTransformBuilder.cs | 5 ++--- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index c0c8e07e6f..8720140e13 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -125,19 +125,7 @@ namespace SixLabors.ImageSharp /// should be power of 2. /// [MethodImpl(InliningOptions.ShortMethod)] - public static int ModuloP2(int x, int m) - { - return x & (m - 1); - } - - /// - /// Converts degrees to radians - /// - [MethodImpl(InliningOptions.ShortMethod)] - public static float DegreesToRadians(float degrees) - { - return degrees * ((float)Math.PI / 180f); - } + public static int ModuloP2(int x, int m) => x & (m - 1); /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index eab75cfdbe..a91d1f0d2a 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder PrependRotationDegrees(float degrees) - => this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.PrependRotationRadians(MathFExtensions.DegreeToRadian(degrees)); /// /// Appends a rotation matrix using the given rotation angle in degrees @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.AppendRotationRadians(MathFExtensions.DegreeToRadian(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 8bde90d51a..ad6ef20bb1 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Collections.Generic; using System.Numerics; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -115,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.PrependRotationRadians(MathFExtensions.DegreeToRadian(degrees)); /// /// Appends a centered rotation matrix using the given rotation in degrees. @@ -123,7 +122,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(ImageMaths.DegreesToRadians(degrees)); + => this.AppendRotationRadians(MathFExtensions.DegreeToRadian(degrees)); /// /// Prepends a scale matrix from the given uniform scale. From cfa7cfd3db4ecdd9d62e7ae14cfc4221dca99473 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Nov 2018 18:22:39 +0000 Subject: [PATCH 213/238] Remove "Matrix" suffix --- src/ImageSharp/Processing/ProjectiveTransformBuilder.cs | 4 ++-- .../Processing/Transforms/ProjectiveTransformTests.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index ad6ef20bb1..dff9bc6d94 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing /// An enumeration that indicates on which corners to taper the rectangle. /// The amount to taper. /// The . - public ProjectiveTransformBuilder PrependTaperMatrix(TaperSide side, TaperCorner corner, float fraction) + public ProjectiveTransformBuilder PrependTaper(TaperSide side, TaperCorner corner, float fraction) => this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); /// @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing /// An enumeration that indicates on which corners to taper the rectangle. /// The amount to taper. /// The . - public ProjectiveTransformBuilder AppendTaperMatrix(TaperSide side, TaperCorner corner, float fraction) + public ProjectiveTransformBuilder AppendTaper(TaperSide side, TaperCorner corner, float fraction) => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); /// diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index 0362d75a0b..9436b7828c 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) - .AppendTaperMatrix(TaperSide.Right, TaperCorner.Both, .5F); + .AppendTaper(TaperSide.Right, TaperCorner.Both, .5F); image.Mutate(i => i.Transform(builder, sampler)); @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms using (Image image = provider.GetImage()) { ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) - .AppendTaperMatrix(taperSide, taperCorner, .5F); + .AppendTaper(taperSide, taperCorner, .5F); image.Mutate(i => i.Transform(builder)); From ffba817bcae3a2895534c037798bf8e30232e06d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Nov 2018 22:59:31 +0000 Subject: [PATCH 214/238] Update dependencies --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 4 ++-- .../Converters/CIeLchToCieLabConverter.cs | 2 +- .../Converters/CieLabToCieLchConverter.cs | 2 +- .../Converters/CieLchuvToCieLuvConverter.cs | 2 +- .../Converters/CieLuvToCieLchuvConverter.cs | 2 +- src/ImageSharp/ImageSharp.csproj | 2 +- src/ImageSharp/Processing/AffineTransformBuilder.cs | 4 ++-- src/ImageSharp/Processing/KnownFilterMatrices.cs | 2 +- .../Processing/ProjectiveTransformBuilder.cs | 9 ++------- .../Processing/Transforms/TransformBuilderTestBase.cs | 10 ++++------ 10 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 1cb3f444f0..ae5069be1d 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -38,8 +38,8 @@ - - + + All diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs index dd352db809..40d8c5bc69 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation // Conversion algorithm described here: // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = MathFExtensions.DegreeToRadian(hDegrees); + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); float a = c * MathF.Cos(hRadians); float b = c * MathF.Sin(hRadians); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs index 81196604e5..2b859205a0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float l = input.L, a = input.A, b = input.B; float c = MathF.Sqrt((a * a) + (b * b)); float hRadians = MathF.Atan2(b, a); - float hDegrees = MathFExtensions.RadianToDegree(hRadians); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); // Wrap the angle round at 360. hDegrees %= 360; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs index 4f5a20bec7..ba5b8bfb79 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation // Conversion algorithm described here: // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = MathFExtensions.DegreeToRadian(hDegrees); + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); float u = c * MathF.Cos(hRadians); float v = c * MathF.Sin(hRadians); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs index 297c18c5c3..3c7d356a5e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float l = input.L, a = input.U, b = input.V; float c = MathF.Sqrt((a * a) + (b * b)); float hRadians = MathF.Atan2(b, a); - float hDegrees = MathFExtensions.RadianToDegree(hRadians); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); // Wrap the angle round at 360. hDegrees %= 360; diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 29d29d50d8..c19c92426f 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -42,7 +42,7 @@ - + All diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index a91d1f0d2a..ed5aa987f4 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder PrependRotationDegrees(float degrees) - => this.PrependRotationRadians(MathFExtensions.DegreeToRadian(degrees)); + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Appends a rotation matrix using the given rotation angle in degrees @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public AffineTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(MathFExtensions.DegreeToRadian(degrees)); + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/src/ImageSharp/Processing/KnownFilterMatrices.cs b/src/ImageSharp/Processing/KnownFilterMatrices.cs index 4f5e3c8697..cf0d19ff85 100644 --- a/src/ImageSharp/Processing/KnownFilterMatrices.cs +++ b/src/ImageSharp/Processing/KnownFilterMatrices.cs @@ -322,7 +322,7 @@ namespace SixLabors.ImageSharp.Processing degrees += 360; } - float radian = MathFExtensions.DegreeToRadian(degrees); + float radian = GeometryUtilities.DegreeToRadian(degrees); float cosRadian = MathF.Cos(radian); float sinRadian = MathF.Sin(radian); diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index dff9bc6d94..750f2f5d0e 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependRotationRadians(MathFExtensions.DegreeToRadian(degrees)); + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Appends a centered rotation matrix using the given rotation in degrees. @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in degrees. /// The . public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(MathFExtensions.DegreeToRadian(degrees)); + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Prepends a scale matrix from the given uniform scale. @@ -247,10 +247,5 @@ namespace SixLabors.ImageSharp.Processing return matrix; } - - /// - /// Removes all matrices from the builder. - /// - public void Clear() => this.matrices.Clear(); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index badf430132..dffa3c7ac6 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -3,8 +3,6 @@ using System; using System.Numerics; - -using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; @@ -128,7 +126,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms var centerPoint = new Vector2(cx, cy); this.AppendRotationDegrees(builder, deg, centerPoint); - var matrix = Matrix3x2.CreateRotation(ImageMaths.DegreesToRadians(deg), centerPoint); + var matrix = Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(deg), centerPoint); var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); @@ -195,13 +193,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void PrependRotationRadians(TBuilder b1, float v, Vector2 vector2); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => - this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees)); + this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees)); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 center) => - this.AppendRotationRadians(builder, ImageMaths.DegreesToRadians(degrees), center); + this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees), center); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); - + private static float Sqrt(float a) => (float)Math.Sqrt(a); } } \ No newline at end of file From 7ea99129b5745fd780b11d4f84a959d1cdb5c406 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Nov 2018 00:46:32 +0000 Subject: [PATCH 215/238] Match APIs --- .../Processing/AffineTransformBuilder.cs | 114 +++++----- .../ProjectiveTransformProcessor.cs | 6 +- .../Processing/ProjectiveTransformBuilder.cs | 210 ++++++++---------- .../Processing/TransformExtensions.cs | 96 +++++--- .../Transforms/AffineTransformBuilderTests.cs | 15 +- .../ProjectiveTransformBuilderTests.cs | 40 +--- .../Transforms/ProjectiveTransformTests.cs | 6 +- .../Transforms/TransformBuilderTestBase.cs | 12 +- 8 files changed, 246 insertions(+), 253 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index ed5aa987f4..29c37d7bf0 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -17,22 +17,13 @@ namespace SixLabors.ImageSharp.Processing private readonly List> matrixFactories = new List>(); /// - /// Prepends a centered rotation matrix using the given rotation in radians. - /// - /// The amount of rotation, in radians. - /// The rotation center point - /// The . - public AffineTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) - => this.PrependMatrix(Matrix3x2.CreateRotation(radians, centerPoint)); - - /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Prepends a rotation matrix using the given rotation angle in degrees + /// and the image center point as rotation center. /// - /// The amount of rotation, in radians. - /// The rotation center point + /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) - => this.AppendMatrix(Matrix3x2.CreateRotation(radians, centerPoint)); + public AffineTransformBuilder PrependRotationDegrees(float degrees) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Prepends a rotation matrix using the given rotation angle in radians @@ -44,31 +35,40 @@ namespace SixLabors.ImageSharp.Processing => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// - /// Appends a rotation matrix using the given rotation angle in radians - /// and the image center point as rotation center. + /// Prepends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. + /// The rotation origin point. /// The . - public AffineTransformBuilder AppendRotationRadians(float radians) - => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + public AffineTransformBuilder PrependRotationRadians(float radians, Vector2 origin) + => this.PrependMatrix(Matrix3x2.CreateRotation(radians, origin)); /// - /// Prepends a rotation matrix using the given rotation angle in degrees + /// Appends a rotation matrix using the given rotation angle in degrees /// and the image center point as rotation center. /// /// The amount of rotation, in degrees. /// The . - public AffineTransformBuilder PrependRotationDegrees(float degrees) - => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + public AffineTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// - /// Appends a rotation matrix using the given rotation angle in degrees + /// Appends a rotation matrix using the given rotation angle in radians /// and the image center point as rotation center. /// - /// The amount of rotation, in degrees. + /// The amount of rotation, in radians. /// The . - public AffineTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + public AffineTransformBuilder AppendRotationRadians(float radians) + => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + public AffineTransformBuilder AppendRotationRadians(float radians, Vector2 origin) + => this.AppendMatrix(Matrix3x2.CreateRotation(radians, origin)); /// /// Prepends a scale matrix from the given uniform scale. @@ -79,12 +79,12 @@ namespace SixLabors.ImageSharp.Processing => this.PrependMatrix(Matrix3x2.CreateScale(scale)); /// - /// Appends a scale matrix from the given uniform scale. + /// Prepends a scale matrix from the given vector scale. /// - /// The uniform scale. + /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder AppendScale(float scale) - => this.AppendMatrix(Matrix3x2.CreateScale(scale)); + public AffineTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); /// /// Prepends a scale matrix from the given vector scale. @@ -95,28 +95,28 @@ namespace SixLabors.ImageSharp.Processing => this.PrependMatrix(Matrix3x2.CreateScale(scales)); /// - /// Appends a scale matrix from the given vector scale. + /// Appends a scale matrix from the given uniform scale. /// - /// The horizontal and vertical scale. + /// The uniform scale. /// The . - public AffineTransformBuilder AppendScale(Vector2 scales) - => this.AppendMatrix(Matrix3x2.CreateScale(scales)); + public AffineTransformBuilder AppendScale(float scale) + => this.AppendMatrix(Matrix3x2.CreateScale(scale)); /// - /// Prepends a scale matrix from the given vector scale. + /// Appends a scale matrix from the given vector scale. /// - /// The horizontal and vertical scale. + /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder PrependScale(SizeF scale) - => this.PrependScale((Vector2)scale); + public AffineTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); /// /// Appends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. /// The . - public AffineTransformBuilder AppendScale(SizeF scales) - => this.AppendScale((Vector2)scales); + public AffineTransformBuilder AppendScale(Vector2 scales) + => this.AppendMatrix(Matrix3x2.CreateScale(scales)); /// /// Prepends a centered skew matrix from the give angles in degrees. @@ -141,66 +141,58 @@ namespace SixLabors.ImageSharp.Processing /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslation(Vector2 position) - => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); + public AffineTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); /// - /// Appends a translation matrix from the given vector. + /// Prepends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslation(Vector2 position) - => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); + public AffineTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); /// - /// Prepends a translation matrix from the given vector. + /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder PrependTranslation(PointF position) - => this.PrependTranslation((Vector2)position); + public AffineTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); /// /// Appends a translation matrix from the given vector. /// /// The translation position. /// The . - public AffineTransformBuilder AppendTranslation(PointF position) - => this.AppendTranslation((Vector2)position); + public AffineTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); /// /// Prepends a raw matrix. /// /// The matrix to prepend. /// The . - public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) - { - this.matrixFactories.Insert(0, _ => matrix); - return this; - } + public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) => this.Prepend(_ => matrix); /// /// Appends a raw matrix. /// /// The matrix to append. /// The . - public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) - { - this.matrixFactories.Add(_ => matrix); - return this; - } + public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) => this.Append(_ => matrix); /// /// Returns the combined matrix for a given source size. /// - /// The source image size + /// The source image size. /// The . public Matrix3x2 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); /// /// Returns the combined matrix for a given source rectangle. /// - /// The rectangle in the source image + /// The rectangle in the source image. /// The . public Matrix3x2 BuildMatrix(Rectangle sourceRectangle) { diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index bfde1769c1..273156e2eb 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -24,13 +24,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The transform matrix. /// The sampler to perform the transform operation. - /// The source image size. - public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size sourceSize) + /// The target dimensions. + public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size targetDimensions) { Guard.NotNull(sampler, nameof(sampler)); this.Sampler = sampler; this.TransformMatrix = matrix; - this.TargetDimensions = TransformUtils.GetTransformedSize(sourceSize, matrix); + this.TargetDimensions = targetDimensions; } /// diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 750f2f5d0e..a905467bba 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; using System.Numerics; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -13,34 +14,7 @@ namespace SixLabors.ImageSharp.Processing /// public class ProjectiveTransformBuilder { - private readonly List matrices = new List(); - private Rectangle sourceRectangle; - - /// - /// Initializes a new instance of the class. - /// - /// The source image size. - public ProjectiveTransformBuilder(Size sourceSize) - : this(new Rectangle(Point.Empty, sourceSize)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The source rectangle. - public ProjectiveTransformBuilder(Rectangle sourceRectangle) - { - Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); - Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); - - this.sourceRectangle = sourceRectangle; - } - - /// - /// Gets the source image size. - /// - internal Size Size => this.sourceRectangle.Size; + private readonly List> matrixFactories = new List>(); /// /// Prepends a matrix that performs a tapering projective transform. @@ -50,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing /// The amount to taper. /// The . public ProjectiveTransformBuilder PrependTaper(TaperSide side, TaperCorner corner, float fraction) - => this.PrependMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + => this.Prepend(size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); /// /// Appends a matrix that performs a tapering projective transform. @@ -60,7 +34,15 @@ namespace SixLabors.ImageSharp.Processing /// The amount to taper. /// The . public ProjectiveTransformBuilder AppendTaper(TaperSide side, TaperCorner corner, float fraction) - => this.AppendMatrix(TransformUtils.CreateTaperMatrix(this.Size, side, corner, fraction)); + => this.Append(size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); + + /// + /// Prepends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder PrependRotationDegrees(float degrees) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Prepends a centered rotation matrix using the given rotation in radians. @@ -68,33 +50,32 @@ namespace SixLabors.ImageSharp.Processing /// The amount of rotation, in radians. /// The . public ProjectiveTransformBuilder PrependRotationRadians(float radians) - { - var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); - return this.PrependMatrix(m); - } + => this.Prepend(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); /// /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. + /// The rotation center. /// The . - public ProjectiveTransformBuilder AppendRotationRadians(float radians) - { - var m = new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, this.Size)); - return this.AppendMatrix(m); - } + internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) + => this.PrependMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0))); + + /// + /// Appends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); /// /// Appends a centered rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. - /// The rotation center. /// The . - internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) - { - var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0)); - return this.PrependMatrix(m); - } + public ProjectiveTransformBuilder AppendRotationRadians(float radians) + => this.Append(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); /// /// Appends a centered rotation matrix using the given rotation in radians. @@ -103,80 +84,69 @@ namespace SixLabors.ImageSharp.Processing /// The rotation center. /// The . internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) - { - var m = Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0)); - return this.AppendMatrix(m); - } + => this.AppendMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0))); /// - /// Prepends a centered rotation matrix using the given rotation in degrees. + /// Prepends a scale matrix from the given uniform scale. /// - /// The amount of rotation, in degrees. - /// The . - public ProjectiveTransformBuilder PrependCenteredRotationDegrees(float degrees) - => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + /// The uniform scale. + /// The . + public ProjectiveTransformBuilder PrependScale(float scale) + => this.PrependMatrix(Matrix4x4.CreateScale(scale)); /// - /// Appends a centered rotation matrix using the given rotation in degrees. + /// Prepends a scale matrix from the given vector scale. /// - /// The amount of rotation, in degrees. - /// The . - public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) - => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); /// - /// Prepends a scale matrix from the given uniform scale. + /// Prepends a scale matrix from the given vector scale. /// - /// The uniform scale. - /// The . - public ProjectiveTransformBuilder PrependScale(float scale) - => this.PrependMatrix(Matrix4x4.CreateScale(scale)); + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(Vector2 scales) + => this.PrependMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1F))); /// /// Appends a scale matrix from the given uniform scale. /// /// The uniform scale. - /// The . + /// The . public ProjectiveTransformBuilder AppendScale(float scale) => this.AppendMatrix(Matrix4x4.CreateScale(scale)); /// - /// Prepends a scale matrix from the given vector scale. + /// Appends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. - /// The . - public ProjectiveTransformBuilder PrependScale(Vector2 scales) - => this.PrependMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f))); + /// The . + public ProjectiveTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); /// /// Appends a scale matrix from the given vector scale. /// /// The horizontal and vertical scale. - /// The . + /// The . public ProjectiveTransformBuilder AppendScale(Vector2 scales) - => this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1f))); - - /// - /// Prepends a scale matrix from the given vector scale. - /// - /// The horizontal and vertical scale. - /// The . - public ProjectiveTransformBuilder PrependScale(SizeF scale) - => this.PrependScale((Vector2)scale); + => this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1F))); /// - /// Appends a scale matrix from the given vector scale. + /// Prepends a translation matrix from the given vector. /// - /// The horizontal and vertical scale. - /// The . - public ProjectiveTransformBuilder AppendScale(SizeF scales) - => this.AppendScale((Vector2)scales); + /// The translation position. + /// The . + public ProjectiveTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); /// /// Prepends a translation matrix from the given vector. /// /// The translation position. - /// The . + /// The . public ProjectiveTransformBuilder PrependTranslation(Vector2 position) => this.PrependMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); @@ -184,68 +154,72 @@ namespace SixLabors.ImageSharp.Processing /// Appends a translation matrix from the given vector. /// /// The translation position. - /// The . - public ProjectiveTransformBuilder AppendTranslation(Vector2 position) - => this.AppendMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); - - /// - /// Prepends a translation matrix from the given vector. - /// - /// The translation position. - /// The . - public ProjectiveTransformBuilder PrependTranslation(PointF position) - => this.PrependTranslation((Vector2)position); + /// The . + public ProjectiveTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); /// /// Appends a translation matrix from the given vector. /// /// The translation position. - /// The . - public ProjectiveTransformBuilder AppendTranslation(PointF position) - => this.AppendTranslation((Vector2)position); + /// The . + public ProjectiveTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); /// /// Prepends a raw matrix. /// /// The matrix to prepend. /// The . - public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) - { - this.matrices.Insert(0, matrix); - return this; - } + public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) => this.Prepend(_ => matrix); /// /// Appends a raw matrix. /// /// The matrix to append. /// The . - public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) - { - this.matrices.Add(matrix); - return this; - } + public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) => this.Append(_ => matrix); + + /// + /// Returns the combined matrix for a given source size. + /// + /// The source image size. + /// The . + public Matrix4x4 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); /// - /// Returns the combined matrix. + /// Returns the combined matrix for a given source rectangle. /// + /// The rectangle in the source image. /// The . - public Matrix4x4 BuildMatrix() + public Matrix4x4 BuildMatrix(Rectangle sourceRectangle) { - Matrix4x4 matrix = Matrix4x4.Identity; + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); // Translate the origin matrix to cater for source rectangle offsets. - if (!this.sourceRectangle.Equals(default)) - { - matrix *= Matrix4x4.CreateTranslation(new Vector3(-this.sourceRectangle.Location, 0)); - } + var matrix = Matrix4x4.CreateTranslation(new Vector3(-sourceRectangle.Location, 0)); + + Size size = sourceRectangle.Size; - foreach (Matrix4x4 m in this.matrices) + foreach (Func factory in this.matrixFactories) { - matrix *= m; + matrix *= factory(size); } return matrix; } + + private ProjectiveTransformBuilder Prepend(Func factory) + { + this.matrixFactories.Insert(0, factory); + return this; + } + + private ProjectiveTransformBuilder Append(Func factory) + { + this.matrixFactories.Add(factory); + return this; + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index de4a3e5ba7..db14b6baf9 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -15,40 +15,32 @@ namespace SixLabors.ImageSharp.Processing public static class TransformExtensions { /// - /// Performs an affine transform of an image using the specified sampling algorithm. + /// Performs an affine transform of an image. /// /// The pixel format. - /// The . - /// The source rectangle - /// The transformation matrix. - /// The size of the result image. - /// The to perform the resampling. + /// The image to transform. + /// The affine transform builder. /// The public static IImageProcessingContext Transform( - this IImageProcessingContext ctx, - Rectangle sourceRectangle, - Matrix3x2 transform, - Size targetDimensions, - IResampler sampler) + this IImageProcessingContext source, + AffineTransformBuilder builder) where TPixel : struct, IPixel - { - return ctx.ApplyProcessor( - new AffineTransformProcessor(transform, sampler, targetDimensions), - sourceRectangle); - } + => Transform(source, builder, KnownResamplers.Bicubic); /// - /// Performs an affine transform of an image. + /// Performs an affine transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. + /// The . /// The affine transform builder. + /// The to perform the resampling. /// The public static IImageProcessingContext Transform( - this IImageProcessingContext source, - AffineTransformBuilder builder) + this IImageProcessingContext ctx, + AffineTransformBuilder builder, + IResampler sampler) where TPixel : struct, IPixel - => Transform(source, builder, KnownResamplers.Bicubic); + => ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); /// /// Performs an affine transform of an image using the specified sampling algorithm. @@ -76,16 +68,22 @@ namespace SixLabors.ImageSharp.Processing /// /// The pixel format. /// The . - /// The affine transform builder. + /// The source rectangle + /// The transformation matrix. + /// The size of the result image. /// The to perform the resampling. /// The public static IImageProcessingContext Transform( this IImageProcessingContext ctx, - AffineTransformBuilder builder, + Rectangle sourceRectangle, + Matrix3x2 transform, + Size targetDimensions, IResampler sampler) where TPixel : struct, IPixel { - return ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); + return ctx.ApplyProcessor( + new AffineTransformProcessor(transform, sampler, targetDimensions), + sourceRectangle); } /// @@ -105,15 +103,59 @@ namespace SixLabors.ImageSharp.Processing /// Performs a projective transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. + /// The . /// The projective transform builder. /// The to perform the resampling. /// The public static IImageProcessingContext Transform( - this IImageProcessingContext source, + this IImageProcessingContext ctx, + ProjectiveTransformBuilder builder, + IResampler sampler) + where TPixel : struct, IPixel + => ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); + + /// + /// Performs a projective transform of an image using the specified sampling algorithm. + /// + /// The pixel format. + /// The . + /// The source rectangle + /// The projective transform builder. + /// The to perform the resampling. + /// The + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, ProjectiveTransformBuilder builder, IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new ProjectiveTransformProcessor(builder.BuildMatrix(), sampler, builder.Size)); + { + Matrix4x4 transform = builder.BuildMatrix(sourceRectangle); + Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform); + return ctx.Transform(sourceRectangle, transform, targetDimensions, sampler); + } + + /// + /// Performs a projective transform of an image using the specified sampling algorithm. + /// + /// The pixel format. + /// The . + /// The source rectangle + /// The transformation matrix. + /// The size of the result image. + /// The to perform the resampling. + /// The + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + Matrix4x4 transform, + Size targetDimensions, + IResampler sampler) + where TPixel : struct, IPixel + { + return ctx.ApplyProcessor( + new ProjectiveTransformProcessor(transform, sampler, targetDimensions), + sourceRectangle); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index e025851684..bdc66641a1 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -1,28 +1,31 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; -using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class AffineTransformBuilderTests : TransformBuilderTestBase { protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => builder.AppendRotationRadians(radians, center); protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => - builder.PrependRotationRadians(radians, center); + + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) => + builder.PrependRotationRadians(radians, origin); protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); @@ -35,4 +38,4 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms return Vector2.Transform(sourcePoint, matrix); } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 01448ac596..287d7be491 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -1,60 +1,40 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using SixLabors.ImageSharp.Processing; using SixLabors.Primitives; -using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class ProjectiveTransformBuilderTests : TransformBuilderTestBase { - [Fact] - public void ConstructorAssignsProperties() - { - var s = new Size(1, 1); - var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); - Assert.Equal(s, builder.Size); - } - - [Fact] - public void ConstructorThrowsInvalid() - { - Assert.Throws(() => - { - var s = new Size(0, 1); - var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); - }); - - Assert.Throws(() => - { - var s = new Size(1, 0); - var builder = new ProjectiveTransformBuilder(new Rectangle(Point.Empty, s)); - }); - } - - protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(rectangle); + protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(); protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => builder.AppendRotationRadians(radians, center); protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); - protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => - builder.PrependRotationRadians(radians, center); + + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => + builder.PrependRotationRadians(radians, origin); protected override Vector2 Execute( ProjectiveTransformBuilder builder, Rectangle rectangle, Vector2 sourcePoint) { - Matrix4x4 matrix = builder.BuildMatrix(); + Matrix4x4 matrix = builder.BuildMatrix(rectangle); return Vector2.Transform(sourcePoint, matrix); } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index 9436b7828c..1da660d222 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder() .AppendTaper(TaperSide.Right, TaperCorner.Both, .5F); image.Mutate(i => i.Transform(builder, sampler)); @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder() .AppendTaper(taperSide, taperCorner, .5F); image.Mutate(i => i.Transform(builder)); @@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Matrix4x4 matrix = Matrix4x4.Identity; matrix.M13 = 0.01F; - ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder(image.Size()) + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder() .AppendMatrix(matrix); image.Mutate(i => i.Transform(builder)); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index dffa3c7ac6..720c87cedf 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -18,7 +18,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms new TheoryData { // scale, translate, source, expectedDest - { Vector2.One, Vector2.Zero, Vector2.Zero, Vector2.Zero }, { Vector2.One, Vector2.Zero, new Vector2(10, 20), new Vector2(10, 20) }, { Vector2.One, new Vector2(3, 1), new Vector2(10, 20), new Vector2(13, 21) }, @@ -44,7 +43,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms new TheoryData { // translate, scale, source, expectedDest - { Vector2.Zero, Vector2.One, Vector2.Zero, Vector2.Zero }, { Vector2.Zero, Vector2.One, new Vector2(10, 20), new Vector2(10, 20) }, { new Vector2(3, 1), new Vector2(2, 0.5f), new Vector2(10, 20), new Vector2(26, 10.5f) }, @@ -183,14 +181,20 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract TBuilder CreateBuilder(Rectangle rectangle); protected abstract void AppendTranslation(TBuilder builder, PointF translate); + protected abstract void AppendScale(TBuilder builder, SizeF scale); + protected abstract void AppendRotationRadians(TBuilder builder, float radians); + protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 center); protected abstract void PrependTranslation(TBuilder builder, PointF translate); + protected abstract void PrependScale(TBuilder builder, SizeF scale); + protected abstract void PrependRotationRadians(TBuilder builder, float radians); - protected abstract void PrependRotationRadians(TBuilder b1, float v, Vector2 vector2); + + protected abstract void PrependRotationRadians(TBuilder builder, float radians, Vector2 origin); protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees)); @@ -199,7 +203,5 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees), center); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); - - private static float Sqrt(float a) => (float)Math.Sqrt(a); } } \ No newline at end of file From a1b74ea1cb3e1fecddcb7af74cb4c48a46734060 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Nov 2018 10:15:52 +0000 Subject: [PATCH 216/238] Add large jpeg to 32bit skip --- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 5977e59cf3..15f7f92a83 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -49,7 +49,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518, TestImages.Jpeg.Issues.InvalidEOI695, - TestImages.Jpeg.Issues.ExifResizeOutOfRange696 + TestImages.Jpeg.Issues.ExifResizeOutOfRange696, + TestImages.Jpeg.Issues.ExifGetString750Transform }; return !TestEnvironment.Is64BitProcess && largeImagesToSkipOn32Bit.Contains(provider.SourceFileOrDescription); From 964ebcc1c30e965ab66be49c99f1dfad5d47e2b9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Nov 2018 10:23:06 +0000 Subject: [PATCH 217/238] Remove unused variables --- .../Processors/Transforms/AffineTransformProcessor.cs | 4 +--- .../Processors/Transforms/ProjectiveTransformProcessor.cs | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index aabaa63cf9..5a3b5943b7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -69,14 +69,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Handle tranforms that result in output identical to the original. if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix3x2.Identity)) { - // The cloned will be blank here copy all the pixel data over + // The clone will be blank here copy all the pixel data over source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); return; } - int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; - var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 273156e2eb..98d488a420 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -65,14 +65,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Handle tranforms that result in output identical to the original. if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix4x4.Identity)) { - // The cloned will be blank here copy all the pixel data over + // The clone will be blank here copy all the pixel data over source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); return; } - int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; - var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. @@ -129,7 +127,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // Use the single precision position to calculate correct bounding pixels // otherwise we get rogue pixels outside of the bounds. - var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix); + var v3 = Vector3.Transform(new Vector3(x, y, 1F), matrix); Vector2 point = new Vector2(v3.X, v3.Y) / MathF.Max(v3.Z, Epsilon); kernel.Convolve(point, x, ref ySpanRef, ref xSpanRef, source.PixelBuffer, vectorSpan); From 35ff16d5a6cb4caf54df2eba7646dc4eabd393b3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Nov 2018 12:12:42 +0000 Subject: [PATCH 218/238] Add Rotate(degrees, origin) --- .../Processing/AffineTransformBuilder.cs | 22 ++++++++++-- .../Processing/ProjectiveTransformBuilder.cs | 34 ++++++++++++++----- .../Transforms/AffineTransformBuilderTests.cs | 7 ++-- .../ProjectiveTransformBuilderTests.cs | 7 ++-- .../Transforms/TransformBuilderTestBase.cs | 8 ++--- 5 files changed, 59 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 29c37d7bf0..ef0b24f815 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -35,7 +35,16 @@ namespace SixLabors.ImageSharp.Processing => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// - /// Prepends a centered rotation matrix using the given rotation in radians. + /// Prepends a rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in degrees. + /// The rotation origin point. + /// The . + public AffineTransformBuilder PrependRotationDegrees(float degrees, Vector2 origin) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Prepends a rotation matrix using the given rotation in radians at the given origin. /// /// The amount of rotation, in radians. /// The rotation origin point. @@ -62,7 +71,16 @@ namespace SixLabors.ImageSharp.Processing => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Appends a rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in degrees. + /// The rotation origin point. + /// The . + public AffineTransformBuilder AppendRotationDegrees(float degrees, Vector2 origin) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Appends a rotation matrix using the given rotation in radians at the given origin. /// /// The amount of rotation, in radians. /// The rotation origin point. diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index a905467bba..5a19b890d9 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -53,13 +53,22 @@ namespace SixLabors.ImageSharp.Processing => this.Prepend(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Prepends a centered rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + internal ProjectiveTransformBuilder PrependRotationDegrees(float degrees, Vector2 origin) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Prepends a centered rotation matrix using the given rotation in radians at the given origin. /// /// The amount of rotation, in radians. - /// The rotation center. + /// The rotation origin point. /// The . - internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 centerPoint) - => this.PrependMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0))); + internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 origin) + => this.PrependMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(origin, 0))); /// /// Appends a centered rotation matrix using the given rotation in degrees. @@ -78,13 +87,22 @@ namespace SixLabors.ImageSharp.Processing => this.Append(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); /// - /// Appends a centered rotation matrix using the given rotation in radians. + /// Appends a centered rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + internal ProjectiveTransformBuilder AppendRotationDegrees(float degrees, Vector2 origin) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Appends a centered rotation matrix using the given rotation in radians at the given origin. /// /// The amount of rotation, in radians. - /// The rotation center. + /// The rotation origin point. /// The . - internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 centerPoint) - => this.AppendMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(centerPoint, 0))); + internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 origin) + => this.AppendMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(origin, 0))); /// /// Prepends a scale matrix from the given uniform scale. diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index bdc66641a1..14b8672641 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -15,8 +15,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 center) => - builder.AppendRotationRadians(radians, center); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); + + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 287d7be491..9f58826cd8 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -17,8 +17,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); - protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 center) => - builder.AppendRotationRadians(radians, center); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); + + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 720c87cedf..43ad756e04 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void AppendRotationRadians(TBuilder builder, float radians); - protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 center); + protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 origin); protected abstract void PrependTranslation(TBuilder builder, PointF translate); @@ -196,11 +196,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract void PrependRotationRadians(TBuilder builder, float radians, Vector2 origin); - protected virtual void AppendRotationDegrees(TBuilder builder, float degrees) => - this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees)); + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees); - protected virtual void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 center) => - this.AppendRotationRadians(builder, GeometryUtilities.DegreeToRadian(degrees), center); + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 origin); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); } From 65ce05d8c961358b4ca1543c901804ccb4a9c7cd Mon Sep 17 00:00:00 2001 From: Anton Firsov Date: Tue, 27 Nov 2018 21:37:57 +0100 Subject: [PATCH 219/238] Update CONTRIBUTING.md --- .github/CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 188c11ff31..19941e65ee 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -20,6 +20,11 @@ * Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes. +#### **Running tests and Debugging** + +* Expected test output is pulled in as a submodule from the [ImageSharp.Tests.Images repository](https://github.com/SixLabors/Imagesharp.Tests.Images/tree/master/ReferenceOutput). To succesfully run tests, make sure that you have updated the submodules! +* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like dotnet/coreclr#16443 or dotnet/coreclr#20657 + #### **Do you have questions about consuming the library or the source code?** * Ask any question about how to use ImageSharp in the [ImageSharp Gitter Chat Room](https://gitter.im/ImageSharp/General). From 836738c5b5e1edf2dab63753e82ea0050e32f931 Mon Sep 17 00:00:00 2001 From: Anton Firsov Date: Tue, 27 Nov 2018 21:41:01 +0100 Subject: [PATCH 220/238] Fix links --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 19941e65ee..01c09d2231 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -23,7 +23,7 @@ #### **Running tests and Debugging** * Expected test output is pulled in as a submodule from the [ImageSharp.Tests.Images repository](https://github.com/SixLabors/Imagesharp.Tests.Images/tree/master/ReferenceOutput). To succesfully run tests, make sure that you have updated the submodules! -* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like dotnet/coreclr#16443 or dotnet/coreclr#20657 +* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like [dotnet/coreclr#16443](https://github.com/dotnet/coreclr/issues/16443) or [dotnet/coreclr#20657](https://github.com/dotnet/coreclr/issues/20657) #### **Do you have questions about consuming the library or the source code?** From 70206614fc55bc20d8512af821450aa090f82137 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 27 Nov 2018 20:44:35 +0100 Subject: [PATCH 221/238] refactor KernelMap initialization --- .../Processors/Transforms/KernelMap.cs | 94 +++++++++++-------- .../KernelMapTests.ReferenceKernelMap.cs | 4 +- .../Processors/Transforms/KernelMapTests.cs | 18 +++- .../Processors/Transforms/ResizeTests.cs | 31 +++++- 4 files changed, 102 insertions(+), 45 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs index 3f2bf8dda4..96eb976495 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -15,28 +15,38 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal class KernelMap : IDisposable { - private readonly Buffer2D data; + private readonly IResampler sampler; - private readonly ResizeKernel[] kernels; + private readonly int sourceSize; + + private readonly float ratio; - private int period; + private readonly float scale; - private int radius; + private readonly int radius; - private int periodicRegionMin; + private readonly Buffer2D data; - private int periodicRegionMax; + private readonly ResizeKernel[] kernels; - private KernelMap(MemoryAllocator memoryAllocator, int destinationSize, int radius, int period) + private KernelMap( + MemoryAllocator memoryAllocator, + IResampler sampler, + int sourceSize, + int destinationSize, + int bufferHeight, + float ratio, + float scale, + int radius) { - this.DestinationSize = destinationSize; - this.period = period; + this.sampler = sampler; + this.ratio = ratio; + this.scale = scale; this.radius = radius; - this.periodicRegionMin = period + radius; - this.periodicRegionMax = destinationSize - radius; - - int width = (radius * 2) + 1; - this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); + this.sourceSize = sourceSize; + this.DestinationSize = destinationSize; + int maxWidth = (radius * 2) + 1; + this.data = memoryAllocator.Allocate2D(maxWidth, bufferHeight, AllocationOptions.Clean); this.kernels = new ResizeKernel[destinationSize]; } @@ -79,61 +89,69 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; - int radius = (int)MathF.Ceiling(scale * sampler.Radius); - var result = new KernelMap(memoryAllocator, destinationSize, radius, period); - for (int i = 0; i < destinationSize; i++) + var result = new KernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + destinationSize, + ratio, + scale, + radius); + + result.BasicInit(); + + return result; + } + + private void BasicInit() + { + for (int i = 0; i < this.DestinationSize; i++) { - float center = ((i + .5F) * ratio) - .5F; + float center = ((i + .5F) * this.ratio) - .5F; // Keep inside bounds. - int left = (int)MathF.Ceiling(center - radius); + int left = (int)MathF.Ceiling(center - this.radius); if (left < 0) { left = 0; } - int right = (int)MathF.Floor(center + radius); - if (right > sourceSize - 1) + int right = (int)MathF.Floor(center + this.radius); + if (right > this.sourceSize - 1) { - right = sourceSize - 1; + right = this.sourceSize - 1; } float sum = 0; - ResizeKernel ws = result.CreateKernel(i, left, right); - result.kernels[i] = ws; + ResizeKernel kernel = this.CreateKernel(i, left, right); + this.kernels[i] = kernel; - ref float weightsBaseRef = ref MemoryMarshal.GetReference(ws.GetValues()); + ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.GetValues()); for (int j = left; j <= right; j++) { - float weight = sampler.GetValue((j - center) / scale); - sum += weight; + float value = this.sampler.GetValue((j - center) / this.scale); + sum += value; // weights[j - left] = weight: - Unsafe.Add(ref weightsBaseRef, j - left) = weight; + Unsafe.Add(ref kernelBaseRef, j - left) = value; } // Normalize, best to do it here rather than in the pixel loop later on. if (sum > 0) { - for (int w = 0; w < ws.Length; w++) + for (int w = 0; w < kernel.Length; w++) { // weights[w] = weights[w] / sum: - ref float wRef = ref Unsafe.Add(ref weightsBaseRef, w); - wRef /= sum; + ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w); + kRef /= sum; } } } - - return result; - } - - private int ReduceIndex(int destIndex) - { - return destIndex; } /// diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index cf0e94e8b4..3786ec6e38 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public ReferenceKernel GetKernel(int destinationIndex) => this.kernels[destinationIndex]; - public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize) + public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize, bool normalize = true) { float ratio = (float)sourceSize / destinationSize; float scale = ratio; @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms result.Add(new ReferenceKernel(left, values)); - if (sum > 0) + if (sum > 0 && normalize) { for (int w = 0; w < values.Length; w++) { diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index c5916ce0be..69de5dbbf2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -35,6 +35,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Bicubic), 500, 200 }, { nameof(KnownResamplers.Bicubic), 200, 500 }, + { nameof(KnownResamplers.Bicubic), 10, 25 }, + { nameof(KnownResamplers.Lanczos3), 16, 12 }, { nameof(KnownResamplers.Lanczos3), 12, 16 }, { nameof(KnownResamplers.Lanczos3), 12, 9 }, @@ -43,12 +45,26 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos3), 8, 6 }, { nameof(KnownResamplers.Lanczos3), 20, 12 }, + { nameof(KnownResamplers.Lanczos3), 5, 25 }, + { nameof(KnownResamplers.Lanczos3), 5, 50 }, + { nameof(KnownResamplers.Lanczos8), 500, 200 }, { nameof(KnownResamplers.Lanczos8), 100, 10 }, { nameof(KnownResamplers.Lanczos8), 100, 80 }, { nameof(KnownResamplers.Lanczos8), 10, 100 }, }; + [Theory] + [MemberData(nameof(KernelMapData))] + public void PrintNonNormalizedKernelMap(string resamplerName, int srcSize, int destSize) + { + IResampler resampler = TestUtils.GetResampler(resamplerName); + + var kernelMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize, false); + + this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); + } + [Theory] [MemberData(nameof(KernelMapData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) @@ -60,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms #if DEBUG this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); - this.Output.WriteLine($"Reference KernelMap:\n{PrintKernelMap(referenceMap)}\n"); + // this.Output.WriteLine($"Reference KernelMap:\n{PrintKernelMap(referenceMap)}\n"); #endif for (int i = 0; i < kernelMap.DestinationSize; i++) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index bec64e4d37..42cb083f13 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -11,6 +11,7 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; using Xunit; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { @@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.07F); - public static readonly TheoryData AllReSamplers = + public static readonly TheoryData AllResamplers = new TheoryData { { "Bicubic", KnownResamplers.Bicubic }, @@ -40,9 +41,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms }; [Theory] - [WithTestPatternImages(nameof(AllReSamplers), 100, 100, DefaultPixelType, 0.5f)] - [WithFileCollection(nameof(CommonTestImages), nameof(AllReSamplers), DefaultPixelType, 0.5f)] - [WithFileCollection(nameof(CommonTestImages), nameof(AllReSamplers), DefaultPixelType, 0.3f)] + [WithTestPatternImages(nameof(AllResamplers), 100, 100, DefaultPixelType, 0.5f)] + [WithFileCollection(nameof(CommonTestImages), nameof(AllResamplers), DefaultPixelType, 0.5f)] + [WithFileCollection(nameof(CommonTestImages), nameof(AllResamplers), DefaultPixelType, 0.3f)] public void Resize_WorksWithAllResamplers(TestImageProvider provider, string name, IResampler sampler, float ratio) where TPixel : struct, IPixel { @@ -57,6 +58,28 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } + [Theory] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 1)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 10)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Lanczos3), 10)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Lanczos8), 10)] + [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 10)] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 1)] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 5)] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 5)] + public void ScaleUp(TestImageProvider provider, string samplerName, float ratio) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage()) + { + SizeF newSize = image.Size() * ratio; + image.Mutate(x => x.Resize((Size)newSize, TestUtils.GetResampler(samplerName), false)); + FormattableString details = $"{samplerName}_{ratio.ToString(System.Globalization.CultureInfo.InvariantCulture)}"; + + image.DebugSave(provider, details); + } + } + [Theory] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 1)] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 4)] From e2ff889f45fbd56d8995ed516fab3388a59b9685 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 00:51:15 +0100 Subject: [PATCH 222/238] rename KernelMap to ResizeKernelMap, introduce MosaicKernelMap, move source code --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 3 +- src/ImageSharp/ImageSharp.csproj.DotSettings | 4 +- .../{ => Resamplers}/BicubicResampler.cs | 0 .../{ => Resamplers}/BoxResampler.cs | 0 .../{ => Resamplers}/CatmullRomResampler.cs | 0 .../{ => Resamplers}/HermiteResampler.cs | 0 .../{ => Resamplers}/Lanczos2Resampler.cs | 0 .../{ => Resamplers}/Lanczos3Resampler.cs | 0 .../{ => Resamplers}/Lanczos5Resampler.cs | 0 .../{ => Resamplers}/Lanczos8Resampler.cs | 0 .../MitchellNetravaliResampler.cs | 0 .../NearestNeighborResampler.cs | 0 .../{ => Resamplers}/RobidouxResampler.cs | 0 .../RobidouxSharpResampler.cs | 0 .../{ => Resamplers}/SplineResampler.cs | 0 .../{ => Resamplers}/TriangleResampler.cs | 0 .../{ => Resamplers}/WelchResampler.cs | 0 .../Transforms/{ => Resize}/ResizeKernel.cs | 22 +++--- .../Resize/ResizeKernelMap.MosaicKernelMap.cs | 46 ++++++++++++ .../ResizeKernelMap.cs} | 70 ++++++++++++------- .../{ => Resize}/ResizeProcessor.cs | 8 +-- .../KernelMapTests.ReferenceKernelMap.cs | 2 +- .../Processors/Transforms/KernelMapTests.cs | 4 +- .../Processors/Transforms/ResizeTests.cs | 1 + 24 files changed, 115 insertions(+), 45 deletions(-) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/BicubicResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/BoxResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/CatmullRomResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/HermiteResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/Lanczos2Resampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/Lanczos3Resampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/Lanczos5Resampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/Lanczos8Resampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/MitchellNetravaliResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/NearestNeighborResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/RobidouxResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/RobidouxSharpResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/SplineResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/TriangleResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resamplers}/WelchResampler.cs (100%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resize}/ResizeKernel.cs (81%) create mode 100644 src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs rename src/ImageSharp/Processing/Processors/Transforms/{KernelMap.cs => Resize/ResizeKernelMap.cs} (69%) rename src/ImageSharp/Processing/Processors/Transforms/{ => Resize}/ResizeProcessor.cs (98%) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index f07ccb03b4..45cb52fd95 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -5,6 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; namespace SixLabors.ImageSharp @@ -98,7 +99,7 @@ namespace SixLabors.ImageSharp /// /// Determine the Least Common Multiple (LCM) of two numbers. - /// TODO: This method might be useful for building a more compact + /// TODO: This method might be useful for building a more compact /// public static int LeastCommonMultiple(int a, int b) { diff --git a/src/ImageSharp/ImageSharp.csproj.DotSettings b/src/ImageSharp/ImageSharp.csproj.DotSettings index cd75f91b7b..a7337240a5 100644 --- a/src/ImageSharp/ImageSharp.csproj.DotSettings +++ b/src/ImageSharp/ImageSharp.csproj.DotSettings @@ -5,4 +5,6 @@ True True True - True \ No newline at end of file + True + True + True \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/BicubicResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/BicubicResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/BoxResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/BoxResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/CatmullRomResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CatmullRomResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/CatmullRomResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/CatmullRomResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/HermiteResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/HermiteResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/HermiteResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/HermiteResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos2Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos2Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos2Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos2Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos3Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos3Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos3Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos3Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos5Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos5Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos5Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos5Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos8Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos8Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos8Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos8Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/MitchellNetravaliResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/MitchellNetravaliResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/MitchellNetravaliResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/MitchellNetravaliResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/NearestNeighborResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/NearestNeighborResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/RobidouxResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/RobidouxResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/RobidouxSharpResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxSharpResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/RobidouxSharpResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxSharpResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/SplineResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/SplineResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/SplineResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/SplineResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/TriangleResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/TriangleResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/WelchResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/WelchResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs similarity index 81% rename from src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index 1ce9c9c91e..1183de7541 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -11,18 +11,21 @@ using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Points to a collection of of weights allocated in . + /// Points to a collection of of weights allocated in . /// - internal struct ResizeKernel + internal unsafe struct ResizeKernel { + private readonly float* bufferPtr; + /// /// Initializes a new instance of the struct. /// [MethodImpl(InliningOptions.ShortMethod)] - internal ResizeKernel(int left, Memory bufferSlice) + internal ResizeKernel(int left, float* bufferPtr, int length) { this.Left = left; - this.BufferSlice = bufferSlice; + this.bufferPtr = bufferPtr; + this.Length = length; } /// @@ -30,22 +33,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// public int Left { get; } - /// - /// Gets the slice of the buffer containing the weights values. - /// - public Memory BufferSlice { get; } - /// /// Gets the the length of the kernel /// - public int Length => this.BufferSlice.Length; + public int Length { get; } /// - /// Gets the span representing the portion of the that this window covers + /// Gets the span representing the portion of the that this window covers /// /// The [MethodImpl(InliningOptions.ShortMethod)] - public Span GetValues() => this.BufferSlice.Span; + public Span GetValues() => new Span(this.bufferPtr, this.Length); /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs new file mode 100644 index 0000000000..b815d05cbc --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs @@ -0,0 +1,46 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains + /// + internal partial class ResizeKernelMap + { + /// + /// Memory-optimized where repeating rows are stored only once. + /// + private sealed class MosaicKernelMap : ResizeKernelMap + { + private readonly int period; + + private readonly int cornerInterval; + + public MosaicKernelMap( + MemoryAllocator memoryAllocator, + IResampler sampler, + int sourceSize, + int destinationSize, + float ratio, + float scale, + int radius, + int period, + int cornerInterval) + : base( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + (cornerInterval * 2) + period, + ratio, + scale, + radius) + { + this.cornerInterval = cornerInterval; + this.period = period; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs similarity index 69% rename from src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 96eb976495..443db72d9e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -11,9 +12,10 @@ using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Holds the values in an optimized contigous memory region. + /// Provides values from an optimized, + /// contigous memory region. /// - internal class KernelMap : IDisposable + internal partial class ResizeKernelMap : IDisposable { private readonly IResampler sampler; @@ -25,11 +27,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly int radius; + private readonly MemoryHandle pinHandle; + private readonly Buffer2D data; private readonly ResizeKernel[] kernels; - private KernelMap( + private ResizeKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, int sourceSize, @@ -47,16 +51,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.DestinationSize = destinationSize; int maxWidth = (radius * 2) + 1; this.data = memoryAllocator.Allocate2D(maxWidth, bufferHeight, AllocationOptions.Clean); + this.pinHandle = this.data.Memory.Pin(); this.kernels = new ResizeKernel[destinationSize]; } public int DestinationSize { get; } /// - /// Disposes instance releasing it's backing buffer. + /// Disposes instance releasing it's backing buffer. /// public void Dispose() { + this.pinHandle.Dispose(); this.data.Dispose(); } @@ -73,8 +79,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The destination size /// The source size /// The to use for buffer allocations - /// The - public static KernelMap Calculate( + /// The + public static ResizeKernelMap Calculate( IResampler sampler, int destinationSize, int sourceSize, @@ -88,25 +94,40 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms scale = 1F; } - int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; int radius = (int)MathF.Ceiling(scale * sampler.Radius); - - var result = new KernelMap( - memoryAllocator, - sampler, - sourceSize, - destinationSize, - destinationSize, - ratio, - scale, - radius); - - result.BasicInit(); + int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; + float center0 = (ratio - 1) * 0.5f; + int cornerInterval = (int)MathF.Ceiling((radius - center0 - 1) / ratio); + + bool useMosaic = 2 * (cornerInterval + period) < destinationSize; + + ResizeKernelMap result = useMosaic + ? new ResizeKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + destinationSize, + ratio, + scale, + radius) + : new MosaicKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + ratio, + scale, + radius, + period, + cornerInterval); + + result.Init(); return result; } - private void BasicInit() + protected virtual void Init() { for (int i = 0; i < this.DestinationSize; i++) { @@ -157,7 +178,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Slices a weights value at the given positions. /// - private ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) + private unsafe ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) { int length = rightIdx - left + 1; @@ -166,10 +187,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width"); } - int flatStartIndex = destIdx * this.data.Width; + Span rowSpan = this.data.GetRowSpan(destIdx); - Memory bufferSlice = this.data.Memory.Slice(flatStartIndex, length); - return new ResizeKernel(left, bufferSlice); + ref float rowReference = ref MemoryMarshal.GetReference(rowSpan); + float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference); + return new ResizeKernel(left, rowPtr, length); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs similarity index 98% rename from src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 7c9d39fc55..189e21de7a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -27,8 +27,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms where TPixel : struct, IPixel { // The following fields are not immutable but are optionally created on demand. - private KernelMap horizontalKernelMap; - private KernelMap verticalKernelMap; + private ResizeKernelMap horizontalKernelMap; + private ResizeKernelMap verticalKernelMap; /// /// Initializes a new instance of the class. @@ -165,13 +165,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // Since all image frame dimensions have to be the same we can calculate this for all frames. MemoryAllocator memoryAllocator = source.GetMemoryAllocator(); - this.horizontalKernelMap = KernelMap.Calculate( + this.horizontalKernelMap = ResizeKernelMap.Calculate( this.Sampler, this.ResizeRectangle.Width, sourceRectangle.Width, memoryAllocator); - this.verticalKernelMap = KernelMap.Calculate( + this.verticalKernelMap = ResizeKernelMap.Calculate( this.Sampler, this.ResizeRectangle.Height, sourceRectangle.Height, diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 3786ec6e38..85a930fb9a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public partial class KernelMapTests { /// - /// Simplified reference implementation for functionality. + /// Simplified reference implementation for functionality. /// internal class ReferenceKernelMap { diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 69de5dbbf2..4d005576c2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms IResampler resampler = TestUtils.GetResampler(resamplerName); var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); - var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); + var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } - private static string PrintKernelMap(KernelMap kernelMap) => + private static string PrintKernelMap(ResizeKernelMap kernelMap) => PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); private static string PrintKernelMap(ReferenceKernelMap kernelMap) => diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 42cb083f13..839d26e71c 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -58,6 +58,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } + // TODO: Merge with the previous theory + add test images [Theory] [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 1)] [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 10)] From e2279a04aa1e5c806b79f31c02bf27b4f83647f1 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 01:12:17 +0100 Subject: [PATCH 223/238] preparations for implementing MosaicKernelMap --- .../Transforms/Resize/ResizeKernel.cs | 12 +- .../Resize/ResizeKernelMap.MosaicKernelMap.cs | 5 + .../Transforms/Resize/ResizeKernelMap.cs | 131 ++++++++++-------- .../KernelMapTests.ReferenceKernelMap.cs | 2 +- .../Processors/Transforms/KernelMapTests.cs | 2 +- 5 files changed, 86 insertions(+), 66 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index 1183de7541..b2d7d21167 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -41,9 +41,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Gets the span representing the portion of the that this window covers /// - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public Span GetValues() => new Span(this.bufferPtr, this.Length); + /// The + /// + public Span Values + { + [MethodImpl(InliningOptions.ShortMethod)] + get => new Span(this.bufferPtr, this.Length); + } /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. @@ -53,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms [MethodImpl(InliningOptions.ShortMethod)] public Vector4 Convolve(Span rowSpan) { - ref float horizontalValues = ref MemoryMarshal.GetReference(this.GetValues()); + ref float horizontalValues = ref Unsafe.AsRef(this.bufferPtr); int left = this.Left; ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs index b815d05cbc..09ae796777 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs @@ -41,6 +41,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.cornerInterval = cornerInterval; this.period = period; } + + protected override void Initialize() + { + base.Initialize(); + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 443db72d9e..ebb15d3768 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } /// - /// Returns a for an index value between 0 and destinationSize - 1. + /// Returns a for an index value between 0 and DestinationSize - 1. /// [MethodImpl(InliningOptions.ShortMethod)] public ref ResizeKernel GetKernel(int destIdx) => ref this.kernels[destIdx]; @@ -101,93 +101,104 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms bool useMosaic = 2 * (cornerInterval + period) < destinationSize; + useMosaic = false; + ResizeKernelMap result = useMosaic - ? new ResizeKernelMap( - memoryAllocator, - sampler, - sourceSize, - destinationSize, - destinationSize, - ratio, - scale, - radius) - : new MosaicKernelMap( - memoryAllocator, - sampler, - sourceSize, - destinationSize, - ratio, - scale, - radius, - period, - cornerInterval); - - result.Init(); + ? new MosaicKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + ratio, + scale, + radius, + period, + cornerInterval) + : new ResizeKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + destinationSize, + ratio, + scale, + radius); + + result.Initialize(); return result; } - protected virtual void Init() + protected virtual void Initialize() { - for (int i = 0; i < this.DestinationSize; i++) + for (int destRowIndex = 0; destRowIndex < this.DestinationSize; destRowIndex++) { - float center = ((i + .5F) * this.ratio) - .5F; + ResizeKernel kernel = this.BuildKernelRow(destRowIndex, destRowIndex); + this.kernels[destRowIndex] = kernel; + } + } - // Keep inside bounds. - int left = (int)MathF.Ceiling(center - this.radius); - if (left < 0) - { - left = 0; - } + private ResizeKernel BuildKernelRow(int destRowIndex, int dataRowIndex) + { + float center = ((destRowIndex + .5F) * this.ratio) - .5F; - int right = (int)MathF.Floor(center + this.radius); - if (right > this.sourceSize - 1) - { - right = this.sourceSize - 1; - } + // Keep inside bounds. + int left = (int)MathF.Ceiling(center - this.radius); + if (left < 0) + { + left = 0; + } - float sum = 0; + int right = (int)MathF.Floor(center + this.radius); + if (right > this.sourceSize - 1) + { + right = this.sourceSize - 1; + } - ResizeKernel kernel = this.CreateKernel(i, left, right); - this.kernels[i] = kernel; + float sum = 0; - ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.GetValues()); + ResizeKernel kernel = this.GetKernel(dataRowIndex, left, right); - for (int j = left; j <= right; j++) - { - float value = this.sampler.GetValue((j - center) / this.scale); - sum += value; + ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values); - // weights[j - left] = weight: - Unsafe.Add(ref kernelBaseRef, j - left) = value; - } + for (int j = left; j <= right; j++) + { + float value = this.sampler.GetValue((j - center) / this.scale); + sum += value; - // Normalize, best to do it here rather than in the pixel loop later on. - if (sum > 0) + // weights[j - left] = weight: + Unsafe.Add(ref kernelBaseRef, j - left) = value; + } + + // Normalize, best to do it here rather than in the pixel loop later on. + if (sum > 0) + { + for (int w = 0; w < kernel.Length; w++) { - for (int w = 0; w < kernel.Length; w++) - { - // weights[w] = weights[w] / sum: - ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w); - kRef /= sum; - } + // weights[w] = weights[w] / sum: + ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w); + kRef /= sum; } } + + return kernel; } /// - /// Slices a weights value at the given positions. + /// Returns a referencing values of + /// at row . /// - private unsafe ResizeKernel CreateKernel(int destIdx, int left, int rightIdx) + private unsafe ResizeKernel GetKernel(int dataRowIndex, int left, int right) { - int length = rightIdx - left + 1; + int length = right - left + 1; if (length > this.data.Width) { - throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width"); + throw new InvalidOperationException( + $"Error in KernelMap.CreateKernel({dataRowIndex},{left},{right}): left > this.data.Width"); } - Span rowSpan = this.data.GetRowSpan(destIdx); + Span rowSpan = this.data.GetRowSpan(dataRowIndex); ref float rowReference = ref MemoryMarshal.GetReference(rowSpan); float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 85a930fb9a..f7c3b27e5a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public static implicit operator ReferenceKernel(ResizeKernel orig) { - return new ReferenceKernel(orig.Left, orig.GetValues().ToArray()); + return new ReferenceKernel(orig.Left, orig.Values.ToArray()); } } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 4d005576c2..7b997e33f2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms Assert.Equal(referenceKernel.Length, kernel.Length); Assert.Equal(referenceKernel.Left, kernel.Left); float[] expectedValues = referenceKernel.Values; - Span actualValues = kernel.GetValues(); + Span actualValues = kernel.Values; Assert.Equal(expectedValues.Length, actualValues.Length); From b33b5687d124ed1bf53368fa6f3403d4bbc6d7c8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 02:16:01 +0100 Subject: [PATCH 224/238] MosaicKernelMap works! --- .../Transforms/Resize/ResizeKernel.cs | 9 ++++-- .../Resize/ResizeKernelMap.MosaicKernelMap.cs | 32 ++++++++++++++++++- .../Transforms/Resize/ResizeKernelMap.cs | 26 +++++++++------ .../Processors/Transforms/KernelMapTests.cs | 16 ++++++++-- 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index b2d7d21167..e10afce2e4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -6,14 +6,12 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; - namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// /// Points to a collection of of weights allocated in . /// - internal unsafe struct ResizeKernel + internal readonly unsafe struct ResizeKernel { private readonly float* bufferPtr; @@ -73,5 +71,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return result; } + + internal ResizeKernel AlterLeftValue(int left) + { + return new ResizeKernel(left, this.bufferPtr, this.Length); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs index 09ae796777..cf660a72f0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs @@ -1,5 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. + +using System; + using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -42,9 +45,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.period = period; } + internal override string Info => base.Info + $"|period:{this.period}|cornerInterval:{this.cornerInterval}"; + protected override void Initialize() { - base.Initialize(); + // Build top corner data + one period of the mosaic data: + int startOfFirstRepeatedMosaic = this.cornerInterval + this.period; + + for (int i = 0; i < startOfFirstRepeatedMosaic; i++) + { + ResizeKernel kernel = this.BuildKernel(i, i); + this.kernels[i] = kernel; + } + + // Copy the mosaics: + int bottomStartDest = this.DestinationSize - this.cornerInterval; + for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) + { + float center = ((i + .5F) * this.ratio) - .5F; + int left = (int)MathF.Ceiling(center - this.radius); + ResizeKernel kernel = this.kernels[i - this.period]; + this.kernels[i] = kernel.AlterLeftValue(left); + } + + // Build bottom corner data: + int bottomStartData = this.cornerInterval + this.period; + for (int i = 0; i < this.cornerInterval; i++) + { + ResizeKernel kernel = this.BuildKernel(bottomStartDest + i, bottomStartData + i); + this.kernels[bottomStartDest + i] = kernel; + } } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index ebb15d3768..262a39352c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -57,6 +57,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public int DestinationSize { get; } + internal virtual string Info => + $"radius:{this.radius}|sourceSize:{this.sourceSize}|destinationSize:{this.DestinationSize}|ratio:{this.ratio}|scale:{this.scale}"; + /// /// Disposes instance releasing it's backing buffer. /// @@ -97,11 +100,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int radius = (int)MathF.Ceiling(scale * sampler.Radius); int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; float center0 = (ratio - 1) * 0.5f; - int cornerInterval = (int)MathF.Ceiling((radius - center0 - 1) / ratio); + float firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; + int cornerInterval = (int)MathF.Ceiling(firstNonNegativeLeftVal); - bool useMosaic = 2 * (cornerInterval + period) < destinationSize; + // corner case for cornerInteval: + if (firstNonNegativeLeftVal == cornerInterval) + { + cornerInterval++; + } - useMosaic = false; + bool useMosaic = 2 * (cornerInterval + period) < destinationSize; ResizeKernelMap result = useMosaic ? new MosaicKernelMap( @@ -131,14 +139,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected virtual void Initialize() { - for (int destRowIndex = 0; destRowIndex < this.DestinationSize; destRowIndex++) + for (int i = 0; i < this.DestinationSize; i++) { - ResizeKernel kernel = this.BuildKernelRow(destRowIndex, destRowIndex); - this.kernels[destRowIndex] = kernel; + ResizeKernel kernel = this.BuildKernel(i, i); + this.kernels[i] = kernel; } } - private ResizeKernel BuildKernelRow(int destRowIndex, int dataRowIndex) + private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex) { float center = ((destRowIndex + .5F) * this.ratio) - .5F; @@ -157,7 +165,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float sum = 0; - ResizeKernel kernel = this.GetKernel(dataRowIndex, left, right); + ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right); ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values); @@ -188,7 +196,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Returns a referencing values of /// at row . /// - private unsafe ResizeKernel GetKernel(int dataRowIndex, int left, int right) + private unsafe ResizeKernel CreateKernel(int dataRowIndex, int left, int right) { int length = right - left + 1; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 7b997e33f2..f0a0d738b9 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -48,6 +48,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos3), 5, 25 }, { nameof(KnownResamplers.Lanczos3), 5, 50 }, + { nameof(KnownResamplers.Lanczos3), 25, 5 }, + { nameof(KnownResamplers.Lanczos3), 50, 5 }, + { nameof(KnownResamplers.Lanczos3), 49, 5 }, + { nameof(KnownResamplers.Lanczos3), 31, 5 }, + { nameof(KnownResamplers.Lanczos8), 500, 200 }, { nameof(KnownResamplers.Lanczos8), 100, 10 }, { nameof(KnownResamplers.Lanczos8), 100, 80 }, @@ -75,8 +80,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG + this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); - // this.Output.WriteLine($"Reference KernelMap:\n{PrintKernelMap(referenceMap)}\n"); #endif for (int i = 0; i < kernelMap.DestinationSize; i++) @@ -92,7 +97,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms Assert.Equal(expectedValues.Length, actualValues.Length); - var comparer = new ApproximateFloatComparer(1e-6f); + var comparer = new ApproximateFloatComparer(1e-4f); for (int x = 0; x < expectedValues.Length; x++) { @@ -116,12 +121,17 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { var bld = new StringBuilder(); + if (kernelMap is ResizeKernelMap actualMap) + { + bld.AppendLine(actualMap.Info); + } + int destinationSize = getDestinationSize(kernelMap); for (int i = 0; i < destinationSize; i++) { ReferenceKernel kernel = getKernel(kernelMap, i); - bld.Append($"({kernel.Left:D3}) || "); + bld.Append($"[{i:D3}] (L{kernel.Left:D3}) || "); Span span = kernel.Values; for (int j = 0; j < kernel.Length; j++) From 2d96beed9acb84a061e96cf824274cb4356a240e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 02:24:35 +0100 Subject: [PATCH 225/238] format, docs, cleanup --- .../Transforms/Resize/ResizeKernel.cs | 4 ++ .../Resize/ResizeKernelMap.MosaicKernelMap.cs | 10 ++--- .../Transforms/Resize/ResizeKernelMap.cs | 37 ++++++++++++------- .../Processors/Transforms/KernelMapTests.cs | 4 +- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index e10afce2e4..04bf6c3a44 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -72,6 +72,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return result; } + /// + /// Copy the contents of altering + /// to the value . + /// internal ResizeKernel AlterLeftValue(int left) { return new ResizeKernel(left, this.bufferPtr, this.Length); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs index cf660a72f0..e106b1ea0a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs @@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public MosaicKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, - int sourceSize, - int destinationSize, + int sourceLength, + int destinationLength, float ratio, float scale, int radius, @@ -34,8 +34,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms : base( memoryAllocator, sampler, - sourceSize, - destinationSize, + sourceLength, + destinationLength, (cornerInterval * 2) + period, ratio, scale, @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } // Copy the mosaics: - int bottomStartDest = this.DestinationSize - this.cornerInterval; + int bottomStartDest = this.DestinationLength - this.cornerInterval; for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) { float center = ((i + .5F) * this.ratio) - .5F; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 262a39352c..ccb57114ae 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -13,13 +13,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// /// Provides values from an optimized, - /// contigous memory region. + /// contiguous memory region. /// internal partial class ResizeKernelMap : IDisposable { private readonly IResampler sampler; - private readonly int sourceSize; + private readonly int sourceLength; private readonly float ratio; @@ -36,8 +36,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private ResizeKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, - int sourceSize, - int destinationSize, + int sourceLength, + int destinationLength, int bufferHeight, float ratio, float scale, @@ -47,18 +47,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.ratio = ratio; this.scale = scale; this.radius = radius; - this.sourceSize = sourceSize; - this.DestinationSize = destinationSize; + this.sourceLength = sourceLength; + this.DestinationLength = destinationLength; int maxWidth = (radius * 2) + 1; this.data = memoryAllocator.Allocate2D(maxWidth, bufferHeight, AllocationOptions.Clean); this.pinHandle = this.data.Memory.Pin(); - this.kernels = new ResizeKernel[destinationSize]; + this.kernels = new ResizeKernel[destinationLength]; } - public int DestinationSize { get; } + /// + /// Gets the length of the destination row/column + /// + public int DestinationLength { get; } + /// + /// Gets a string of information to help debugging + /// internal virtual string Info => - $"radius:{this.radius}|sourceSize:{this.sourceSize}|destinationSize:{this.DestinationSize}|ratio:{this.ratio}|scale:{this.scale}"; + $"radius:{this.radius}|sourceSize:{this.sourceLength}|destinationSize:{this.DestinationLength}|ratio:{this.ratio}|scale:{this.scale}"; /// /// Disposes instance releasing it's backing buffer. @@ -104,7 +110,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int cornerInterval = (int)MathF.Ceiling(firstNonNegativeLeftVal); // corner case for cornerInteval: - if (firstNonNegativeLeftVal == cornerInterval) + if (firstNonNegativeLeftVal == cornerInterval) { cornerInterval++; } @@ -139,13 +145,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected virtual void Initialize() { - for (int i = 0; i < this.DestinationSize; i++) + for (int i = 0; i < this.DestinationLength; i++) { ResizeKernel kernel = this.BuildKernel(i, i); this.kernels[i] = kernel; } } + /// + /// Builds a for the row (in ) + /// referencing the data at row within , + /// so the data reusable by other data rows. + /// private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex) { float center = ((destRowIndex + .5F) * this.ratio) - .5F; @@ -158,9 +169,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } int right = (int)MathF.Floor(center + this.radius); - if (right > this.sourceSize - 1) + if (right > this.sourceLength - 1) { - right = this.sourceSize - 1; + right = this.sourceLength - 1; } float sum = 0; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index f0a0d738b9..af98b99521 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); #endif - for (int i = 0; i < kernelMap.DestinationSize; i++) + for (int i = 0; i < kernelMap.DestinationLength; i++) { ResizeKernel kernel = kernelMap.GetKernel(i); @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } private static string PrintKernelMap(ResizeKernelMap kernelMap) => - PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); + PrintKernelMap(kernelMap, km => km.DestinationLength, (km, i) => km.GetKernel(i)); private static string PrintKernelMap(ReferenceKernelMap kernelMap) => PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); From 8cdb72888db1200b5d8dc333989a8150dd38bb11 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 28 Nov 2018 14:21:53 +0000 Subject: [PATCH 226/238] Add Skew methods and tests. --- .../Processing/AffineTransformBuilder.cs | 58 ++++++++++++ .../Processors/Transforms/TransformUtils.cs | 12 +++ .../Processing/ProjectiveTransformBuilder.cs | 76 +++++++++++++++ .../Transforms/AffineTransformBuilderTests.cs | 51 +++++++--- .../ProjectiveTransformBuilderTests.cs | 30 ++++-- .../Transforms/TransformBuilderTestBase.cs | 94 ++++++++++++++++--- 6 files changed, 291 insertions(+), 30 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index ef0b24f815..c3d01241c9 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -145,6 +145,35 @@ namespace SixLabors.ImageSharp.Processing public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) => this.Prepend(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); + /// + /// Prepends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY) + => this.Prepend(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size)); + + /// + /// Prepends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.PrependSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Prepends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.PrependMatrix(Matrix3x2.CreateSkew(radiansX, radiansY, origin)); + /// /// Appends a centered skew matrix from the give angles in degrees. /// @@ -154,6 +183,35 @@ namespace SixLabors.ImageSharp.Processing public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) => this.Append(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); + /// + /// Appends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public AffineTransformBuilder AppendSkewRadians(float radiansX, float radiansY) + => this.Append(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size)); + + /// + /// Appends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.AppendSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Appends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public AffineTransformBuilder AppendSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.AppendMatrix(Matrix3x2.CreateSkew(radiansX, radiansY, origin)); + /// /// Prepends a translation matrix from the given vector. /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs index 6cef38f8fe..24b15d3098 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -46,6 +46,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms new Rectangle(Point.Empty, size), Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty)); + /// + /// Creates a centered skew matrix from the give angles in radians and the source size. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The source image size. + /// The . + public static Matrix3x2 CreateSkewMatrixRadians(float radiansX, float radiansY, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateSkew(radiansX, radiansY, PointF.Empty)); + /// /// Gets the centered transform matrix based upon the source and destination rectangles. /// diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 5a19b890d9..c29941d071 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -152,6 +152,82 @@ namespace SixLabors.ImageSharp.Processing public ProjectiveTransformBuilder AppendScale(Vector2 scales) => this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1F))); + /// + /// Prepends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + internal ProjectiveTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) + => this.PrependSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY)); + + /// + /// Prepends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public ProjectiveTransformBuilder PrependSkewRadians(float radiansX, float radiansY) + => this.Prepend(size => new Matrix4x4(TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size))); + + /// + /// Prepends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder PrependSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.PrependSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Prepends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder PrependSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.PrependMatrix(new Matrix4x4(Matrix3x2.CreateSkew(radiansX, radiansY, origin))); + + /// + /// Appends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + internal ProjectiveTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) + => this.AppendSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY)); + + /// + /// Appends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public ProjectiveTransformBuilder AppendSkewRadians(float radiansX, float radiansY) + => this.Append(size => new Matrix4x4(TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size))); + + /// + /// Appends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder AppendSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.AppendSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Appends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder AppendSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.AppendMatrix(new Matrix4x4(Matrix3x2.CreateSkew(radiansX, radiansY, origin))); + /// /// Prepends a translation matrix from the given vector. /// diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 14b8672641..70159e18ac 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -9,28 +9,55 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class AffineTransformBuilderTests : TransformBuilderTestBase { - protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); - protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees) + => builder.AppendRotationDegrees(degrees); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees, Vector2 origin) + => builder.AppendRotationDegrees(degrees, origin); - protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) + => builder.AppendRotationRadians(radians); - protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) + => builder.AppendRotationRadians(radians, origin); - protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); + protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) + => builder.AppendScale(scale); - protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void AppendSkewDegrees(AffineTransformBuilder builder, float degreesX, float degreesY) + => builder.AppendSkewDegrees(degreesX, degreesY); - protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void AppendSkewDegrees(AffineTransformBuilder builder, float degreesX, float degreesY, Vector2 origin) + => builder.AppendSkewDegrees(degreesX, degreesY, origin); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void AppendSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY) + => builder.AppendSkewRadians(radiansX, radiansY); - protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) => - builder.PrependRotationRadians(radians, origin); + protected override void AppendSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.AppendSkewRadians(radiansX, radiansY, origin); - protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); + protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) + => builder.AppendTranslation(translate); + + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) + => builder.PrependRotationRadians(radians); + + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) + => builder.PrependRotationRadians(radians, origin); + + protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) + => builder.PrependScale(scale); + + protected override void PrependSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY) + => builder.PrependSkewRadians(radiansX, radiansY); + + protected override void PrependSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.PrependSkewRadians(radiansX, radiansY, origin); + + protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) + => builder.PrependTranslation(translate); protected override Vector2 Execute( AffineTransformBuilder builder, diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 9f58826cd8..d82cd1689d 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -11,24 +11,42 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(); - protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); - protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); - protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); - protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); + protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY) + => builder.AppendSkewDegrees(degreesX, degreesY); - protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY, Vector2 origin) + => builder.AppendSkewDegrees(degreesX, degreesY, origin); - protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + protected override void AppendSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY) + => builder.AppendSkewRadians(radiansX, radiansY); + + protected override void AppendSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.AppendSkewRadians(radiansX, radiansY, origin); + + protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + + protected override void PrependSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY) + => builder.PrependSkewRadians(radiansX, radiansY); + + protected override void PrependSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.PrependSkewRadians(radiansX, radiansY, origin); + + protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.PrependRotationRadians(radians, origin); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 43ad756e04..71e3b71797 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -86,17 +86,17 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void AppendRotationDegrees_WithoutSpecificRotationCenter_RotationIsCenteredAroundImageCenter( int width, int height, - float deg, + float degrees, float x, float y) { var size = new Size(width, height); TBuilder builder = this.CreateBuilder(size); - this.AppendRotationDegrees(builder, deg); + this.AppendRotationDegrees(builder, degrees); // TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness - Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(deg, size); + Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(degrees, size); var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void AppendRotationDegrees_WithRotationCenter( int width, int height, - float deg, + float degrees, float cx, float cy, float x, @@ -122,9 +122,63 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms TBuilder builder = this.CreateBuilder(size); var centerPoint = new Vector2(cx, cy); - this.AppendRotationDegrees(builder, deg, centerPoint); + this.AppendRotationDegrees(builder, degrees, centerPoint); - var matrix = Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(deg), centerPoint); + var matrix = Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(degrees), centerPoint); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 10, 42, 84)] + [InlineData(200, 100, 100, 100, 42, 84)] + [InlineData(100, 200, -10, -10, 42, 84)] + public void AppendSkewDegrees_WithoutSpecificSkewCenter_SkewIsCenteredAroundImageCenter( + int width, + int height, + float degreesX, + float degreesY, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + this.AppendSkewDegrees(builder, degreesX, degreesY); + + Matrix3x2 matrix = TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 10, 30, 61, 42, 84)] + [InlineData(200, 100, 100, 100, 30, 10, 20, 84)] + [InlineData(100, 200, -10, -10, 30, 20, 11, 84)] + public void AppendSkewDegrees_WithSkewCenter( + int width, + int height, + float degreesX, + float degreesY, + float cx, + float cy, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + var centerPoint = new Vector2(cx, cy); + this.AppendSkewDegrees(builder, degreesX, degreesY, centerPoint); + + var matrix = Matrix3x2.CreateSkew(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), centerPoint); var position = new Vector2(x, y); var expected = Vector2.Transform(position, matrix); @@ -144,14 +198,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms // Forwards this.AppendRotationRadians(b1, pi); + this.AppendSkewRadians(b1, pi, pi); this.AppendScale(b1, new SizeF(2, 0.5f)); this.AppendRotationRadians(b1, pi / 2, new Vector2(-0.5f, -0.1f)); + this.AppendSkewRadians(b1, pi, pi / 2, new Vector2(-0.5f, -0.1f)); this.AppendTranslation(b1, new PointF(123, 321)); // Backwards this.PrependTranslation(b2, new PointF(123, 321)); + this.PrependSkewRadians(b2, pi, pi / 2, new Vector2(-0.5f, -0.1f)); this.PrependRotationRadians(b2, pi / 2, new Vector2(-0.5f, -0.1f)); this.PrependScale(b2, new SizeF(2, 0.5f)); + this.PrependSkewRadians(b2, pi, pi); this.PrependRotationRadians(b2, pi); Vector2 p1 = this.Execute(b1, rectangle, new Vector2(32, 65)); @@ -180,25 +238,37 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected abstract TBuilder CreateBuilder(Rectangle rectangle); - protected abstract void AppendTranslation(TBuilder builder, PointF translate); + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees); - protected abstract void AppendScale(TBuilder builder, SizeF scale); + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 origin); protected abstract void AppendRotationRadians(TBuilder builder, float radians); protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 origin); - protected abstract void PrependTranslation(TBuilder builder, PointF translate); + protected abstract void AppendScale(TBuilder builder, SizeF scale); - protected abstract void PrependScale(TBuilder builder, SizeF scale); + protected abstract void AppendSkewDegrees(TBuilder builder, float degreesX, float degreesY); + + protected abstract void AppendSkewDegrees(TBuilder builder, float degreesX, float degreesY, Vector2 origin); + + protected abstract void AppendSkewRadians(TBuilder builder, float radiansX, float radiansY); + + protected abstract void AppendSkewRadians(TBuilder builder, float radiansX, float radiansY, Vector2 origin); + + protected abstract void AppendTranslation(TBuilder builder, PointF translate); protected abstract void PrependRotationRadians(TBuilder builder, float radians); protected abstract void PrependRotationRadians(TBuilder builder, float radians, Vector2 origin); - protected abstract void AppendRotationDegrees(TBuilder builder, float degrees); + protected abstract void PrependScale(TBuilder builder, SizeF scale); - protected abstract void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 origin); + protected abstract void PrependSkewRadians(TBuilder builder, float radiansX, float radiansY); + + protected abstract void PrependSkewRadians(TBuilder builder, float radiansX, float radiansY, Vector2 origin); + + protected abstract void PrependTranslation(TBuilder builder, PointF translate); protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); } From 2742e1923c369bc880d9649aa7fa3c1ebb3a92d0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 18:44:28 +0100 Subject: [PATCH 227/238] cleanup & undo WIP project setup --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 3 +-- src/ImageSharp/ImageSharp.csproj | 3 +-- ...KernelMap.cs => ResizeKernelMap.PeriodicKernelMap.cs} | 6 +++--- .../Processors/Transforms/Resize/ResizeKernelMap.cs | 2 +- tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 3 +-- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +-- .../Transforms/KernelMapTests.ReferenceKernelMap.cs | 6 +++--- .../Processing/Processors/Transforms/KernelMapTests.cs | 9 ++++----- 8 files changed, 15 insertions(+), 20 deletions(-) rename src/ImageSharp/Processing/Processors/Transforms/Resize/{ResizeKernelMap.MosaicKernelMap.cs => ResizeKernelMap.PeriodicKernelMap.cs} (94%) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 6341e1771c..1cb3f444f0 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -5,8 +5,7 @@ $(packageversion) 0.0.1 SixLabors and contributors - - netcoreapp2.1 + netstandard1.3;netstandard2.0 7.3 true true diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index e2f55e3c6a..29d29d50d8 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,8 +5,7 @@ $(packageversion) 0.0.1 Six Labors and contributors - - netcoreapp2.1 + netstandard1.3;netstandard2.0;netcoreapp2.1;net472 true true SixLabors.ImageSharp diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs similarity index 94% rename from src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs index e106b1ea0a..b7b581c185 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs @@ -8,20 +8,20 @@ using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Contains + /// Contains /// internal partial class ResizeKernelMap { /// /// Memory-optimized where repeating rows are stored only once. /// - private sealed class MosaicKernelMap : ResizeKernelMap + private sealed class PeriodicKernelMap : ResizeKernelMap { private readonly int period; private readonly int cornerInterval; - public MosaicKernelMap( + public PeriodicKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, int sourceLength, diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index ccb57114ae..011a4ffa22 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms bool useMosaic = 2 * (cornerInterval + period) < destinationSize; ResizeKernelMap result = useMosaic - ? new MosaicKernelMap( + ? new PeriodicKernelMap( memoryAllocator, sampler, sourceSize, diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 04a4541b21..a705c9bacb 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,7 +1,6 @@  - - netcoreapp2.1 + netcoreapp2.1;net461 Exe True SixLabors.ImageSharp.Benchmarks diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 75ac7450c8..86c1a7a259 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,7 +1,6 @@  - - netcoreapp2.1 + net462;net472;netcoreapp2.1 True latest full diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index f7c3b27e5a..12c7016096 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms scale = 1F; } - float radius = MathF.Ceiling(scale * sampler.Radius); + float radius = (float)Math.Ceiling(scale * sampler.Radius); var result = new List(); @@ -42,13 +42,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms float center = ((i + .5F) * ratio) - .5F; // Keep inside bounds. - int left = (int)MathF.Ceiling(center - radius); + int left = (int)Math.Ceiling(center - radius); if (left < 0) { left = 0; } - int right = (int)MathF.Floor(center + radius); + int right = (int)Math.Floor(center + radius); if (right > sourceSize - 1) { right = sourceSize - 1; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index af98b99521..962c599e6a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -1,12 +1,11 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Text; -using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; -using SixLabors.Primitives; using Xunit; using Xunit.Abstractions; From 03324e3c218ee97ce13f2d7cecf9dd4d2ef9cf58 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 23:20:57 +0100 Subject: [PATCH 228/238] additional extensive testing --- .../KernelMapTests.ReferenceKernelMap.cs | 21 +++--- .../Processors/Transforms/KernelMapTests.cs | 70 +++++++++++++++++-- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 12c7016096..9a7052b5a8 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -25,21 +26,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize, bool normalize = true) { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; + double ratio = (double)sourceSize / destinationSize; + double scale = ratio; if (scale < 1F) { scale = 1F; } - float radius = (float)Math.Ceiling(scale * sampler.Radius); + double radius = (double)Math.Ceiling(scale * sampler.Radius); var result = new List(); for (int i = 0; i < destinationSize; i++) { - float center = ((i + .5F) * ratio) - .5F; + double center = ((i + .5) * ratio) - .5; // Keep inside bounds. int left = (int)Math.Ceiling(center - radius); @@ -54,20 +55,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms right = sourceSize - 1; } - float sum = 0; + double sum = 0; - float[] values = new float[right - left + 1]; + double[] values = new double[right - left + 1]; for (int j = left; j <= right; j++) { - float weight = sampler.GetValue((j - center) / scale); + double weight = sampler.GetValue((float)((j - center) / scale)); sum += weight; values[j - left] = weight; } - result.Add(new ReferenceKernel(left, values)); - if (sum > 0 && normalize) { for (int w = 0; w < values.Length; w++) @@ -75,6 +74,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms values[w] /= sum; } } + + float[] floatVals = values.Select(v => (float)v).ToArray(); + + result.Add(new ReferenceKernel(left, floatVals)); } return new ReferenceKernelMap(result.ToArray()); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index 962c599e6a..dfbd7a28be 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -2,6 +2,9 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; using System.Text; using SixLabors.ImageSharp.Processing; @@ -58,6 +61,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos8), 10, 100 }, }; + public static TheoryData GeneratedImageResizeData = + GenerateImageResizeData(); + + [Theory] [MemberData(nameof(KernelMapData))] public void PrintNonNormalizedKernelMap(string resamplerName, int srcSize, int destSize) @@ -71,7 +78,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [Theory] [MemberData(nameof(KernelMapData))] + //[MemberData(nameof(GeneratedImageResizeData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) + { + VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + } + + [Theory] + [MemberData(nameof(GeneratedImageResizeData))] + public void KernelMapContentIsCorrect_ExtendedGeneratedValues(string resamplerName, int srcSize, int destSize) + { + VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + } + + + private static void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { IResampler resampler = TestUtils.GetResampler(resamplerName); @@ -79,8 +100,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG - this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); - this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); + // this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); + // this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); #endif for (int i = 0; i < kernelMap.DestinationLength; i++) @@ -89,14 +110,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms ReferenceKernel referenceKernel = referenceMap.GetKernel(i); - Assert.Equal(referenceKernel.Length, kernel.Length); - Assert.Equal(referenceKernel.Left, kernel.Left); + Assert.True( + referenceKernel.Length == kernel.Length, + $"referenceKernel.Length != kernel.Length: {referenceKernel.Length} != {kernel.Length}"); + Assert.True( + referenceKernel.Left == kernel.Left, + $"referenceKernel.Left != kernel.Left: {referenceKernel.Left} != {kernel.Left}"); float[] expectedValues = referenceKernel.Values; Span actualValues = kernel.Values; - + Assert.Equal(expectedValues.Length, actualValues.Length); - var comparer = new ApproximateFloatComparer(1e-4f); + var comparer = new ApproximateFloatComparer(1e-6f); for (int x = 0; x < expectedValues.Length; x++) { @@ -145,5 +170,38 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms return bld.ToString(); } + + + private static TheoryData GenerateImageResizeData() + { + var result = new TheoryData(); + + string[] resamplerNames = typeof(KnownResamplers).GetProperties(BindingFlags.Public | BindingFlags.Static) + .Select(p => p.Name).ToArray(); + + int[] dimensionVals = + { + // Arbitrary, small dimensions: + 9, 10, 11, 13, 49, 50, 53, 99, 100, 199, 200, 201, 299, 300, 301, + + // Typical image sizes: + 640, 480, 800, 600, 1024, 768, 1280, 960, 1536, 1180, 1600, 1200, 2048, 1536, 2240, 1680, 2560, + 1920, 3032, 2008, 3072, 2304, 3264, 2448 + }; + + IOrderedEnumerable<(int s, int d)> source2Dest = dimensionVals + .SelectMany(s => dimensionVals.Select(d => (s, d))) + .OrderBy(x => x.s + x.d); + + foreach (string resampler in resamplerNames) + { + foreach ((int s, int d) x in source2Dest) + { + result.Add(resampler, x.s, x.d); + } + } + + return result; + } } } \ No newline at end of file From ee1f398b1e13b76eb3a244ddfaed0640b5a58526 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 28 Nov 2018 23:21:30 +0100 Subject: [PATCH 229/238] use double precision in KernelMap calculations --- .../Transforms/Resize/ResizeKernel.cs | 10 +++ .../ResizeKernelMap.PeriodicKernelMap.cs | 8 +-- .../Transforms/Resize/ResizeKernelMap.cs | 66 ++++++++++--------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index 04bf6c3a44..f349634ac0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -80,5 +80,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { return new ResizeKernel(left, this.bufferPtr, this.Length); } + + internal void Fill(Span values) + { + DebugGuard.IsTrue(values.Length == this.Length, nameof(values), "ResizeKernel.Fill: values.Length != this.Length!"); + + for (int i = 0; i < this.Length; i++) + { + this.Values[i] = (float)values[i]; + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs index b7b581c185..e0f5ad2613 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs @@ -26,8 +26,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms IResampler sampler, int sourceLength, int destinationLength, - float ratio, - float scale, + double ratio, + double scale, int radius, int period, int cornerInterval) @@ -62,8 +62,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int bottomStartDest = this.DestinationLength - this.cornerInterval; for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) { - float center = ((i + .5F) * this.ratio) - .5F; - int left = (int)MathF.Ceiling(center - this.radius); + double center = ((i + .5) * this.ratio) - .5; + int left = (int)Math.Ceiling(center - this.radius); ResizeKernel kernel = this.kernels[i - this.period]; this.kernels[i] = kernel.AlterLeftValue(left); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 011a4ffa22..4cd9928d30 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -17,13 +17,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal partial class ResizeKernelMap : IDisposable { + private readonly MemoryAllocator memoryAllocator; + private readonly IResampler sampler; private readonly int sourceLength; - private readonly float ratio; + private readonly double ratio; - private readonly float scale; + private readonly double scale; private readonly int radius; @@ -39,10 +41,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int sourceLength, int destinationLength, int bufferHeight, - float ratio, - float scale, + double ratio, + double scale, int radius) { + this.memoryAllocator = memoryAllocator; this.sampler = sampler; this.ratio = ratio; this.scale = scale; @@ -95,19 +98,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int sourceSize, MemoryAllocator memoryAllocator) { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; + double ratio = (double)sourceSize / destinationSize; + double scale = ratio; if (scale < 1F) { scale = 1F; } - int radius = (int)MathF.Ceiling(scale * sampler.Radius); + int radius = (int)Math.Ceiling(scale * sampler.Radius); int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; - float center0 = (ratio - 1) * 0.5f; - float firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; - int cornerInterval = (int)MathF.Ceiling(firstNonNegativeLeftVal); + double center0 = (ratio - 1) * 0.5f; + double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; + int cornerInterval = (int)Math.Ceiling(firstNonNegativeLeftVal); // corner case for cornerInteval: if (firstNonNegativeLeftVal == cornerInterval) @@ -159,45 +162,48 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex) { - float center = ((destRowIndex + .5F) * this.ratio) - .5F; + double center = ((destRowIndex + .5) * this.ratio) - .5; // Keep inside bounds. - int left = (int)MathF.Ceiling(center - this.radius); + int left = (int)Math.Ceiling(center - this.radius); if (left < 0) { left = 0; } - int right = (int)MathF.Floor(center + this.radius); + int right = (int)Math.Floor(center + this.radius); if (right > this.sourceLength - 1) { right = this.sourceLength - 1; } - float sum = 0; - ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right); - ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values); - - for (int j = left; j <= right; j++) + using (IMemoryOwner tempBuffer = this.memoryAllocator.Allocate(kernel.Length)) { - float value = this.sampler.GetValue((j - center) / this.scale); - sum += value; + Span kernelValues = tempBuffer.GetSpan(); + double sum = 0; - // weights[j - left] = weight: - Unsafe.Add(ref kernelBaseRef, j - left) = value; - } + for (int j = left; j <= right; j++) + { + double value = this.sampler.GetValue((float)((j - center) / this.scale)); + sum += value; - // Normalize, best to do it here rather than in the pixel loop later on. - if (sum > 0) - { - for (int w = 0; w < kernel.Length; w++) + kernelValues[j - left] = value; + } + + // Normalize, best to do it here rather than in the pixel loop later on. + if (sum > 0) { - // weights[w] = weights[w] / sum: - ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w); - kRef /= sum; + for (int j = 0; j < kernel.Length; j++) + { + // weights[w] = weights[w] / sum: + ref double kRef = ref kernelValues[j]; + kRef /= sum; + } } + + kernel.Fill(kernelValues); } return kernel; From 97357b45e461a67e6cbe7c437c86cab3c5574d56 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 01:05:07 +0100 Subject: [PATCH 230/238] cherry pick test cases from auto-generated set --- .../Processors/Transforms/KernelMapTests.cs | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index dfbd7a28be..d0ff62a911 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -59,6 +59,30 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos8), 100, 10 }, { nameof(KnownResamplers.Lanczos8), 100, 80 }, { nameof(KnownResamplers.Lanczos8), 10, 100 }, + + // Accuracy-related regression-test cases cherry-picked from GeneratedImageResizeData + { nameof(KnownResamplers.Box), 201, 100 }, + { nameof(KnownResamplers.Box), 199, 99 }, + { nameof(KnownResamplers.Box), 10, 299 }, + { nameof(KnownResamplers.Box), 299, 10 }, + { nameof(KnownResamplers.Box), 301, 300 }, + { nameof(KnownResamplers.Box), 1180, 480 }, + + { nameof(KnownResamplers.Lanczos2), 3264, 3032 }, + + { nameof(KnownResamplers.Bicubic), 1280, 2240 }, + { nameof(KnownResamplers.Bicubic), 1920, 1680 }, + { nameof(KnownResamplers.Bicubic), 3072, 2240 }, + + { nameof(KnownResamplers.Welch), 300, 2008 }, + + // ResizeKernel.Length -related regression tests cherry-picked from GeneratedImageResizeData + { nameof(KnownResamplers.Bicubic), 10, 50 }, + { nameof(KnownResamplers.Bicubic), 49, 301 }, + { nameof(KnownResamplers.Bicubic), 301, 49 }, + { nameof(KnownResamplers.Bicubic), 1680, 1200 }, + { nameof(KnownResamplers.Box), 13, 299 }, + { nameof(KnownResamplers.Lanczos5), 3032, 600 }, }; public static TheoryData GeneratedImageResizeData = @@ -78,18 +102,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [Theory] [MemberData(nameof(KernelMapData))] - //[MemberData(nameof(GeneratedImageResizeData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); } + // Comprehensive but expensive tests, for KernelMap generation + // Enabling them can kill your IDE: +#if false [Theory] [MemberData(nameof(GeneratedImageResizeData))] public void KernelMapContentIsCorrect_ExtendedGeneratedValues(string resamplerName, int srcSize, int destSize) { VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); } +#endif private static void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) @@ -103,6 +130,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms // this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); // this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); #endif + var comparer = new ApproximateFloatComparer(1e-6f); for (int i = 0; i < kernelMap.DestinationLength; i++) { @@ -121,7 +149,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms Assert.Equal(expectedValues.Length, actualValues.Length); - var comparer = new ApproximateFloatComparer(1e-6f); + for (int x = 0; x < expectedValues.Length; x++) { @@ -177,7 +205,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var result = new TheoryData(); string[] resamplerNames = typeof(KnownResamplers).GetProperties(BindingFlags.Public | BindingFlags.Static) - .Select(p => p.Name).ToArray(); + .Select(p => p.Name) + .Where(name => name != nameof(KnownResamplers.NearestNeighbor)) + .ToArray(); int[] dimensionVals = { From 3189c91563f3a4cb805b68137e5f4dd11c4b98e5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 02:34:49 +0100 Subject: [PATCH 231/238] introduce TolerantMath --- src/ImageSharp/Common/Helpers/TolerantMath.cs | 75 ++++++++++ .../Transforms/Resize/ResizeKernelMap.cs | 47 ++++--- .../Helpers/ImageMathsTests.cs | 3 +- .../Helpers/TolerantMathTests.cs | 130 ++++++++++++++++++ .../KernelMapTests.ReferenceKernelMap.cs | 6 + .../Processors/Transforms/KernelMapTests.cs | 15 +- 6 files changed, 243 insertions(+), 33 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/TolerantMath.cs create mode 100644 tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs diff --git a/src/ImageSharp/Common/Helpers/TolerantMath.cs b/src/ImageSharp/Common/Helpers/TolerantMath.cs new file mode 100644 index 0000000000..b9b3b8ea13 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/TolerantMath.cs @@ -0,0 +1,75 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp +{ + /// + /// Implements math operations using tolerant comparison. + /// + internal struct TolerantMath + { + private readonly double epsilon; + + private readonly double negEpsilon; + + public TolerantMath(double epsilon) + { + DebugGuard.MustBeGreaterThan(epsilon, 0, nameof(epsilon)); + + this.epsilon = epsilon; + this.negEpsilon = -epsilon; + } + + public static TolerantMath Default { get; } = new TolerantMath(1e-8); + + /// + /// == 0 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsZero(double a) => a > this.negEpsilon && a < this.epsilon; + + /// + /// > 0 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsPositive(double a) => a > this.epsilon; + + /// + /// < 0 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsNegative(double a) => a < this.negEpsilon; + + /// + /// == + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool AreEqual(double a, double b) => this.IsZero(a - b); + + /// + /// > + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsGreater(double a, double b) => a > b + this.epsilon; + + /// + /// < + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsLess(double a, double b) => a < b - this.epsilon; + + /// + /// >= + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsGreaterOrEqual(double a, double b) => a >= b - this.epsilon; + + /// + /// <= + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsLessOrEqual(double a, double b) => b >= a - this.epsilon; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 4cd9928d30..468e0d8447 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -17,8 +17,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal partial class ResizeKernelMap : IDisposable { - private readonly MemoryAllocator memoryAllocator; - private readonly IResampler sampler; private readonly int sourceLength; @@ -35,6 +33,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ResizeKernel[] kernels; + // To avoid both GC allocations, and MemoryAllocator ceremony: + private readonly double[] tempValues; + private ResizeKernelMap( MemoryAllocator memoryAllocator, IResampler sampler, @@ -45,7 +46,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms double scale, int radius) { - this.memoryAllocator = memoryAllocator; this.sampler = sampler; this.ratio = ratio; this.scale = scale; @@ -56,6 +56,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms this.data = memoryAllocator.Allocate2D(maxWidth, bufferHeight, AllocationOptions.Clean); this.pinHandle = this.data.Memory.Pin(); this.kernels = new ResizeKernel[destinationLength]; + this.tempValues = new double[maxWidth]; } /// @@ -113,7 +114,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int cornerInterval = (int)Math.Ceiling(firstNonNegativeLeftVal); // corner case for cornerInteval: - if (firstNonNegativeLeftVal == cornerInterval) + // TODO: Implement library-wide utils for tolerant comparison + if (Math.Abs(firstNonNegativeLeftVal - cornerInterval) < 1e-8) { cornerInterval++; } @@ -179,33 +181,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right); - using (IMemoryOwner tempBuffer = this.memoryAllocator.Allocate(kernel.Length)) - { - Span kernelValues = tempBuffer.GetSpan(); - double sum = 0; + Span kernelValues = this.tempValues.AsSpan().Slice(0, kernel.Length); + double sum = 0; - for (int j = left; j <= right; j++) - { - double value = this.sampler.GetValue((float)((j - center) / this.scale)); - sum += value; + for (int j = left; j <= right; j++) + { + double value = this.sampler.GetValue((float)((j - center) / this.scale)); + sum += value; - kernelValues[j - left] = value; - } + kernelValues[j - left] = value; + } - // Normalize, best to do it here rather than in the pixel loop later on. - if (sum > 0) + // Normalize, best to do it here rather than in the pixel loop later on. + if (sum > 0) + { + for (int j = 0; j < kernel.Length; j++) { - for (int j = 0; j < kernel.Length; j++) - { - // weights[w] = weights[w] / sum: - ref double kRef = ref kernelValues[j]; - kRef /= sum; - } + // weights[w] = weights[w] / sum: + ref double kRef = ref kernelValues[j]; + kRef /= sum; } - - kernel.Fill(kernelValues); } + kernel.Fill(kernelValues); + return kernel; } diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 75ef611a5c..018fabd982 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -2,11 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; +using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers { - using Xunit; - public class ImageMathsTests { [Theory] diff --git a/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs new file mode 100644 index 0000000000..d488d6491d --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs @@ -0,0 +1,130 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +using Xunit; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Tests.Helpers +{ + public class TolerantMathTests + { + private readonly TolerantMath tolerantMath = new TolerantMath(0.1); + + [Theory] + [InlineData(0)] + [InlineData(0.01)] + [InlineData(-0.05)] + public void IsZero_WhenTrue(double a) + { + Assert.True(this.tolerantMath.IsZero(a)); + } + + [Theory] + [InlineData(0.11)] + [InlineData(-0.101)] + [InlineData(42)] + public void IsZero_WhenFalse(double a) + { + Assert.False(this.tolerantMath.IsZero(a)); + } + + [Theory] + [InlineData(0.11)] + [InlineData(100)] + public void IsPositive_WhenTrue(double a) + { + Assert.True(this.tolerantMath.IsPositive(a)); + } + + [Theory] + [InlineData(0.09)] + [InlineData(-0.1)] + [InlineData(-1000)] + public void IsPositive_WhenFalse(double a) + { + Assert.False(this.tolerantMath.IsPositive(a)); + } + + [Theory] + [InlineData(-0.11)] + [InlineData(-100)] + public void IsNegative_WhenTrue(double a) + { + Assert.True(this.tolerantMath.IsNegative(a)); + } + + [Theory] + [InlineData(-0.09)] + [InlineData(0.1)] + [InlineData(1000)] + public void IsNegative_WhenFalse(double a) + { + Assert.False(this.tolerantMath.IsNegative(a)); + } + + [Theory] + [InlineData(4.2, 4.2)] + [InlineData(4.2, 4.25)] + [InlineData(-Math.PI, -Math.PI + 0.05)] + [InlineData(999999.2, 999999.25)] + public void AreEqual_WhenTrue(double a, double b) + { + Assert.True(this.tolerantMath.AreEqual(a, b)); + } + + [Theory] + [InlineData(1, 2)] + [InlineData(-1000000, -1000000.2)] + public void AreEqual_WhenFalse(double a, double b) + { + Assert.False(this.tolerantMath.AreEqual(a, b)); + } + + [Theory] + [InlineData(2, 1.8)] + [InlineData(-20, -20.2)] + [InlineData(0.1, -0.1)] + [InlineData(100, 10)] + public void IsGreater_IsLess_WhenTrue(double a, double b) + { + Assert.True(this.tolerantMath.IsGreater(a, b)); + Assert.True(this.tolerantMath.IsLess(b, a)); + } + + [Theory] + [InlineData(2, 1.95)] + [InlineData(-20, -20.02)] + [InlineData(0.01, -0.01)] + [InlineData(999999, 999999.09)] + public void IsGreater_IsLess_WhenFalse(double a, double b) + { + Assert.False(this.tolerantMath.IsGreater(a, b)); + Assert.False(this.tolerantMath.IsLess(b, a)); + } + + [Theory] + [InlineData(3, 2)] + [InlineData(3, 2.99)] + [InlineData(2.99, 3)] + [InlineData(-5, -6)] + [InlineData(-5, -5.05)] + [InlineData(-5.05, -5)] + public void IsGreaterOrEqual_IsLessOrEqual_WhenTrue(double a, double b) + { + Assert.True(this.tolerantMath.IsGreaterOrEqual(a, b)); + Assert.True(this.tolerantMath.IsLessOrEqual(b, a)); + } + + [Theory] + [InlineData(2, 3)] + [InlineData(2.89, 3)] + [InlineData(-3, -2.89)] + public void IsGreaterOrEqual_IsLessOrEqual_WhenFalse(double a, double b) + { + Assert.False(this.tolerantMath.IsGreaterOrEqual(a, b)); + Assert.False(this.tolerantMath.IsLessOrEqual(b, a)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 9a7052b5a8..31907b06d3 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -40,6 +41,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms for (int i = 0; i < destinationSize; i++) { + if (i == 21 || i == 64) + { + Debug.Print("lol"); + } + double center = ((i + .5) * ratio) - .5; // Keep inside bounds. diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index d0ff62a911..dc7a441e99 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -104,22 +104,23 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [MemberData(nameof(KernelMapData))] public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { - VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + this.VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); } - // Comprehensive but expensive tests, for KernelMap generation - // Enabling them can kill your IDE: + // Comprehensive but expensive tests, for ResizeKernelMap. + // Enabling them can kill you, but sometimes you have to wear the burden! + // AppVeyor will never follow you to these shadows of Mordor. #if false [Theory] [MemberData(nameof(GeneratedImageResizeData))] public void KernelMapContentIsCorrect_ExtendedGeneratedValues(string resamplerName, int srcSize, int destSize) { - VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + this.VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); } #endif - private static void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) + private void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { IResampler resampler = TestUtils.GetResampler(resamplerName); @@ -127,8 +128,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); #if DEBUG - // this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); - // this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); + this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); + this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); #endif var comparer = new ApproximateFloatComparer(1e-6f); From 49ef404552c15929c5d83a4e93b361df4325c11a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 02:54:31 +0100 Subject: [PATCH 232/238] TolerantMath: implemented Floor and Ceiling --- src/ImageSharp/Common/Helpers/TolerantMath.cs | 28 +++++++++++++- .../Helpers/TolerantMathTests.cs | 38 +++++++++++++++++++ .../ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/TolerantMath.cs b/src/ImageSharp/Common/Helpers/TolerantMath.cs index b9b3b8ea13..d95aea9de2 100644 --- a/src/ImageSharp/Common/Helpers/TolerantMath.cs +++ b/src/ImageSharp/Common/Helpers/TolerantMath.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp { /// - /// Implements math operations using tolerant comparison. + /// Implements basic math operations using tolerant comparison + /// whenever an equality check is needed. /// internal struct TolerantMath { @@ -71,5 +73,29 @@ namespace SixLabors.ImageSharp /// [MethodImpl(InliningOptions.ShortMethod)] public bool IsLessOrEqual(double a, double b) => b >= a - this.epsilon; + + [MethodImpl(InliningOptions.ShortMethod)] + public double Ceiling(double a) + { + double rem = Math.IEEERemainder(a, 1); + if (this.IsZero(rem)) + { + return Math.Round(a); + } + + return Math.Ceiling(a); + } + + [MethodImpl(InliningOptions.ShortMethod)] + public double Floor(double a) + { + double rem = Math.IEEERemainder(a, 1); + if (this.IsZero(rem)) + { + return Math.Round(a); + } + + return Math.Floor(a); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs index d488d6491d..6c7a1f2752 100644 --- a/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs +++ b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs @@ -126,5 +126,43 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.False(this.tolerantMath.IsGreaterOrEqual(a, b)); Assert.False(this.tolerantMath.IsLessOrEqual(b, a)); } + + [Theory] + [InlineData(3.5, 4.0)] + [InlineData(3.89, 4.0)] + [InlineData(4.09, 4.0)] + [InlineData(4.11, 5.0)] + [InlineData(0.11, 1)] + [InlineData(0.05, 0)] + [InlineData(-0.5, 0)] + [InlineData(-0.95, -1)] + [InlineData(-1.05, -1)] + [InlineData(-1.5, -1)] + public void Ceiling(double value, double expected) + { + double actual = this.tolerantMath.Ceiling(value); + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(1, 1)] + [InlineData(0.99, 1)] + [InlineData(0.5, 0)] + [InlineData(0.01, 0)] + [InlineData(-0.09, 0)] + [InlineData(-0.11, -1)] + [InlineData(-100.11, -101)] + [InlineData(-100.09, -100)] + public void Floor(double value, double expected) + { + double plz1 = Math.IEEERemainder(1.1, 1); + double plz2 = Math.IEEERemainder(0.9, 1); + + double plz3 = Math.IEEERemainder(-1.1, 1); + double plz4 = Math.IEEERemainder(-0.9, 1); + + double actual = this.tolerantMath.Floor(value); + Assert.Equal(expected, actual); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 86c1a7a259..75ac7450c8 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,6 +1,7 @@  - net462;net472;netcoreapp2.1 + + netcoreapp2.1 True latest full From b4271cc20d17b148b9e312211b2b339a1d172b98 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 03:05:38 +0100 Subject: [PATCH 233/238] robust ResizeKernelMap calculations using TolerantMath --- .../Resize/ResizeKernelMap.PeriodicKernelMap.cs | 2 +- .../Transforms/Resize/ResizeKernelMap.cs | 15 ++++++++------- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +-- .../KernelMapTests.ReferenceKernelMap.cs | 16 +++++++++------- .../Processors/Transforms/KernelMapTests.cs | 1 - 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs index e0f5ad2613..4b81aaa64e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) { double center = ((i + .5) * this.ratio) - .5; - int left = (int)Math.Ceiling(center - this.radius); + int left = (int)TolerantMath.Ceiling(center - this.radius); ResizeKernel kernel = this.kernels[i - this.period]; this.kernels[i] = kernel.AlterLeftValue(left); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 468e0d8447..347aaf0be0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal partial class ResizeKernelMap : IDisposable { + private static readonly TolerantMath TolerantMath = TolerantMath.Default; + private readonly IResampler sampler; private readonly int sourceLength; @@ -107,15 +109,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms scale = 1F; } - int radius = (int)Math.Ceiling(scale * sampler.Radius); + int radius = (int)TolerantMath.Ceiling(scale * sampler.Radius); int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; - double center0 = (ratio - 1) * 0.5f; + double center0 = (ratio - 1) * 0.5; double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; - int cornerInterval = (int)Math.Ceiling(firstNonNegativeLeftVal); + int cornerInterval = (int)TolerantMath.Ceiling(firstNonNegativeLeftVal); // corner case for cornerInteval: - // TODO: Implement library-wide utils for tolerant comparison - if (Math.Abs(firstNonNegativeLeftVal - cornerInterval) < 1e-8) + if (TolerantMath.AreEqual(firstNonNegativeLeftVal, cornerInterval)) { cornerInterval++; } @@ -167,13 +168,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms double center = ((destRowIndex + .5) * this.ratio) - .5; // Keep inside bounds. - int left = (int)Math.Ceiling(center - this.radius); + int left = (int)TolerantMath.Ceiling(center - this.radius); if (left < 0) { left = 0; } - int right = (int)Math.Floor(center + this.radius); + int right = (int)TolerantMath.Floor(center + this.radius); if (right > this.sourceLength - 1) { right = this.sourceLength - 1; diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 75ac7450c8..86c1a7a259 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,7 +1,6 @@  - - netcoreapp2.1 + net462;net472;netcoreapp2.1 True latest full diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs index 31907b06d3..54ac239ae9 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs @@ -35,27 +35,29 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms scale = 1F; } - double radius = (double)Math.Ceiling(scale * sampler.Radius); + TolerantMath tolerantMath = TolerantMath.Default; + + double radius = tolerantMath.Ceiling(scale * sampler.Radius); var result = new List(); for (int i = 0; i < destinationSize; i++) { - if (i == 21 || i == 64) - { - Debug.Print("lol"); - } + //if (i == 21 || i == 64) + //{ + // Debug.Print("lol"); + //} double center = ((i + .5) * ratio) - .5; // Keep inside bounds. - int left = (int)Math.Ceiling(center - radius); + int left = (int)tolerantMath.Ceiling(center - radius); if (left < 0) { left = 0; } - int right = (int)Math.Floor(center + radius); + int right = (int)tolerantMath.Floor(center + radius); if (right > sourceSize - 1) { right = sourceSize - 1; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index dc7a441e99..c9f20cd272 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -119,7 +119,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } #endif - private void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) { IResampler resampler = TestUtils.GetResampler(resamplerName); From 25195a74f14f4cf0d52422422a134920f55332c0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 03:54:29 +0100 Subject: [PATCH 234/238] update submodule, skip debug-only test case --- .../Processing/Processors/Transforms/KernelMapTests.cs | 6 +++++- tests/Images/External | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index c9f20cd272..783c3c5af6 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -60,6 +60,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { nameof(KnownResamplers.Lanczos8), 100, 80 }, { nameof(KnownResamplers.Lanczos8), 10, 100 }, + // Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Box-0.5: + { nameof(KnownResamplers.Box), 378, 149 }, + { nameof(KnownResamplers.Box), 349, 174 }, + // Accuracy-related regression-test cases cherry-picked from GeneratedImageResizeData { nameof(KnownResamplers.Box), 201, 100 }, { nameof(KnownResamplers.Box), 199, 99 }, @@ -89,7 +93,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms GenerateImageResizeData(); - [Theory] + [Theory(Skip = "Only for debugging and development")] [MemberData(nameof(KernelMapData))] public void PrintNonNormalizedKernelMap(string resamplerName, int srcSize, int destSize) { diff --git a/tests/Images/External b/tests/Images/External index ed8a7b0b6f..5b18d8c95a 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit ed8a7b0b6fe1b2e2a7c822aa617103ae31192655 +Subproject commit 5b18d8c95acffb773012881870ba6f521ba13128 From d4ff2a44f02ac703e32575a81f764805c257389b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 04:14:46 +0100 Subject: [PATCH 235/238] remove outdated TODO note --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 45cb52fd95..9e03c0d3d8 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -99,7 +99,6 @@ namespace SixLabors.ImageSharp /// /// Determine the Least Common Multiple (LCM) of two numbers. - /// TODO: This method might be useful for building a more compact /// public static int LeastCommonMultiple(int a, int b) { From 77e72c8000653fd806c6c4af412d27a8f436b050 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 14:51:06 +0100 Subject: [PATCH 236/238] test code cleanup --- ...esizeKernelMapTests.ReferenceKernelMap.cs} | 12 ++++------ ...nelMapTests.cs => ResizeKernelMapTests.cs} | 4 ++-- .../Processors/Transforms/ResizeTests.cs | 23 ------------------- 3 files changed, 6 insertions(+), 33 deletions(-) rename tests/ImageSharp.Tests/Processing/Processors/Transforms/{KernelMapTests.ReferenceKernelMap.cs => ResizeKernelMapTests.ReferenceKernelMap.cs} (93%) rename tests/ImageSharp.Tests/Processing/Processors/Transforms/{KernelMapTests.cs => ResizeKernelMapTests.cs} (98%) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs similarity index 93% rename from tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs rename to tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs index 54ac239ae9..7d842c4e1e 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs @@ -1,13 +1,14 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using SixLabors.ImageSharp.Processing.Processors.Transforms; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { - public partial class KernelMapTests + public partial class ResizeKernelMapTests { /// /// Simplified reference implementation for functionality. @@ -43,11 +44,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms for (int i = 0; i < destinationSize; i++) { - //if (i == 21 || i == 64) - //{ - // Debug.Print("lol"); - //} - double center = ((i + .5) * ratio) - .5; // Keep inside bounds. diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs similarity index 98% rename from tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs rename to tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs index 783c3c5af6..08b2949139 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs @@ -15,11 +15,11 @@ using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { - public partial class KernelMapTests + public partial class ResizeKernelMapTests { private ITestOutputHelper Output { get; } - public KernelMapTests(ITestOutputHelper output) + public ResizeKernelMapTests(ITestOutputHelper output) { this.Output = output; } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 839d26e71c..b4aff53e82 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -58,29 +58,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } - // TODO: Merge with the previous theory + add test images - [Theory] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 1)] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 10)] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Lanczos3), 10)] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Lanczos8), 10)] - [WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 10)] - [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 1)] - [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.NearestNeighbor), 5)] - [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 5)] - public void ScaleUp(TestImageProvider provider, string samplerName, float ratio) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage()) - { - SizeF newSize = image.Size() * ratio; - image.Mutate(x => x.Resize((Size)newSize, TestUtils.GetResampler(samplerName), false)); - FormattableString details = $"{samplerName}_{ratio.ToString(System.Globalization.CultureInfo.InvariantCulture)}"; - - image.DebugSave(provider, details); - } - } - [Theory] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 1)] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 4)] From 772cdda9780267e89d95e2a9d7ea504e1736745d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 16:49:46 +0100 Subject: [PATCH 237/238] better comments + TolerantMath made readonly --- src/ImageSharp/Common/Helpers/TolerantMath.cs | 2 +- .../Transforms/Resize/ResizeKernelMap.cs | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/TolerantMath.cs b/src/ImageSharp/Common/Helpers/TolerantMath.cs index d95aea9de2..5347efcc09 100644 --- a/src/ImageSharp/Common/Helpers/TolerantMath.cs +++ b/src/ImageSharp/Common/Helpers/TolerantMath.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp /// Implements basic math operations using tolerant comparison /// whenever an equality check is needed. /// - internal struct TolerantMath + internal readonly struct TolerantMath { private readonly double epsilon; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 347aaf0be0..f6edf97865 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -110,20 +110,33 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } int radius = (int)TolerantMath.Ceiling(scale * sampler.Radius); + + // 'ratio' is a rational number. + // Multiplying it by LCM(sourceSize, destSize)/sourceSize will result in a whole number "again". + // This value is determining the length of the periods in repeating kernel map rows. int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; + + // the center position at i == 0: double center0 = (ratio - 1) * 0.5; double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; + + // The number of rows building a "stairway" at the top and the bottom of the kernel map + // corresponding to the corners of the image. + // If we do not normalize the kernel values, these rows also fit the periodic logic, + // however, it's just simpler to calculate them separately. int cornerInterval = (int)TolerantMath.Ceiling(firstNonNegativeLeftVal); - // corner case for cornerInteval: + // If firstNonNegativeLeftVal was an integral value, we don't need Ceiling: if (TolerantMath.AreEqual(firstNonNegativeLeftVal, cornerInterval)) { cornerInterval++; } - bool useMosaic = 2 * (cornerInterval + period) < destinationSize; + // If 'cornerInterval' is too big compared to 'period', we can't apply the periodic optimization. + // If we don't have at least 2 periods, we go with the basic implementation: + bool hasAtLeast2Periods = 2 * (cornerInterval + period) < destinationSize; - ResizeKernelMap result = useMosaic + ResizeKernelMap result = hasAtLeast2Periods ? new PeriodicKernelMap( memoryAllocator, sampler, From ab4cae48ace9d4f8d0586b49241164a43ad76a4f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 29 Nov 2018 17:03:46 +0100 Subject: [PATCH 238/238] improve comments again --- .../Processors/Transforms/Resize/ResizeKernelMap.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index f6edf97865..2ab574df2a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -104,9 +104,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms double ratio = (double)sourceSize / destinationSize; double scale = ratio; - if (scale < 1F) + if (scale < 1) { - scale = 1F; + scale = 1; } int radius = (int)TolerantMath.Ceiling(scale * sampler.Radius); @@ -126,7 +126,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // however, it's just simpler to calculate them separately. int cornerInterval = (int)TolerantMath.Ceiling(firstNonNegativeLeftVal); - // If firstNonNegativeLeftVal was an integral value, we don't need Ceiling: + // If firstNonNegativeLeftVal was an integral value, we need firstNonNegativeLeftVal+1 + // instead of Ceiling: if (TolerantMath.AreEqual(firstNonNegativeLeftVal, cornerInterval)) { cornerInterval++;