From b440d51331e5c8c7f88ac6b50f498f4fce77747d Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 5 Jul 2021 20:27:20 +0200 Subject: [PATCH] Write hasAlpha flag when encoding lossless webp --- .../Formats/WebP/Lossless/Vp8LEncoder.cs | 24 +- .../Formats/WebP/Lossy/YuvConversion.cs | 311 +++--------- .../Formats/WebP/WebpCommonUtils.cs | 165 ++++++ .../Formats/WebP/WebpCommonUtilsTests.cs | 214 ++++++++ .../Formats/WebP/WebpDecoderTests.cs | 12 + .../Formats/WebP/YuvConversionTests.cs | 480 +++++++++++------- tests/ImageSharp.Tests/TestImages.cs | 38 +- .../Input/WebP/lossless_alpha_small.webp | 3 + 8 files changed, 793 insertions(+), 454 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs create mode 100644 tests/Images/Input/WebP/lossless_alpha_small.webp diff --git a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs index d6a5de07a0..5b86cd4c28 100644 --- a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs @@ -194,14 +194,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless where TPixel : unmanaged, IPixel { image.Metadata.SyncProfiles(); - - // Write the image size. int width = image.Width; int height = image.Height; + + // Convert image pixels to bgra array. + bool hasAlpha = this.ConvertPixelsToBgra(image, width, height); + + // Write the image size. this.WriteImageSize(width, height); // Write the non-trivial Alpha flag and lossless version. - bool hasAlpha = false; // TODO: for the start, this will be always false. this.WriteAlphaAndVersion(hasAlpha); // Encode the main image stream. @@ -249,8 +251,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless int width = image.Width; int height = image.Height; - // Convert image pixels to bgra array. - this.ConvertPixelsToBgra(image, width, height); ReadOnlySpan bgra = this.Bgra.GetSpan(); Span encodedData = this.EncodedData.GetSpan(); @@ -345,17 +345,27 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless /// The image to convert. /// The width of the image. /// The height of the image. - private void ConvertPixelsToBgra(Image image, int width, int height) + /// true, if the image is non opaque. + private bool ConvertPixelsToBgra(Image image, int width, int height) where TPixel : unmanaged, IPixel { + bool nonOpaque = false; Span bgra = this.Bgra.GetSpan(); Span bgraBytes = MemoryMarshal.Cast(bgra); int widthBytes = width * 4; for (int y = 0; y < height; y++) { Span rowSpan = image.GetPixelRowSpan(y); - PixelOperations.Instance.ToBgra32Bytes(this.configuration, rowSpan, bgraBytes.Slice(y * widthBytes, widthBytes), width); + Span rowBytes = bgraBytes.Slice(y * widthBytes, widthBytes); + PixelOperations.Instance.ToBgra32Bytes(this.configuration, rowSpan, rowBytes, width); + if (!nonOpaque) + { + Span rowBgra = MemoryMarshal.Cast(rowBytes); + nonOpaque = WebpCommonUtils.CheckNonOpaque(rowBgra); + } } + + return nonOpaque; } /// diff --git a/src/ImageSharp/Formats/WebP/Lossy/YuvConversion.cs b/src/ImageSharp/Formats/WebP/Lossy/YuvConversion.cs index 3c67bfb574..1b970eb45a 100644 --- a/src/ImageSharp/Formats/WebP/Lossy/YuvConversion.cs +++ b/src/ImageSharp/Formats/WebP/Lossy/YuvConversion.cs @@ -4,15 +4,9 @@ using System; using System.Buffers; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; -#if SUPPORTS_RUNTIME_INTRINSICS -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -#endif - namespace SixLabors.ImageSharp.Formats.Webp.Lossy { internal static class YuvConversion @@ -43,218 +37,59 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy // Temporary storage for accumulated R/G/B values during conversion to U/V. using IMemoryOwner tmpRgb = memoryAllocator.Allocate(4 * uvWidth); - using IMemoryOwner rgbaRow0Buffer = memoryAllocator.Allocate(width); - using IMemoryOwner rgbaRow1Buffer = memoryAllocator.Allocate(width); + using IMemoryOwner bgraRow0Buffer = memoryAllocator.Allocate(width); + using IMemoryOwner bgraRow1Buffer = memoryAllocator.Allocate(width); Span tmpRgbSpan = tmpRgb.GetSpan(); - Span rgbaRow0 = rgbaRow0Buffer.GetSpan(); - Span rgbaRow1 = rgbaRow1Buffer.GetSpan(); + Span bgraRow0 = bgraRow0Buffer.GetSpan(); + Span bgraRow1 = bgraRow1Buffer.GetSpan(); int uvRowIndex = 0; int rowIndex; for (rowIndex = 0; rowIndex < height - 1; rowIndex += 2) { Span rowSpan = image.GetPixelRowSpan(rowIndex); Span nextRowSpan = image.GetPixelRowSpan(rowIndex + 1); - PixelOperations.Instance.ToRgba32(configuration, rowSpan, rgbaRow0); - PixelOperations.Instance.ToRgba32(configuration, nextRowSpan, rgbaRow1); + PixelOperations.Instance.ToBgra32(configuration, rowSpan, bgraRow0); + PixelOperations.Instance.ToBgra32(configuration, nextRowSpan, bgraRow1); - bool rowsHaveAlpha = CheckNonOpaque(rgbaRow0) && CheckNonOpaque(rgbaRow1); + bool rowsHaveAlpha = WebpCommonUtils.CheckNonOpaque(bgraRow0) && WebpCommonUtils.CheckNonOpaque(bgraRow1); // Downsample U/V planes, two rows at a time. if (!rowsHaveAlpha) { - AccumulateRgb(rgbaRow0, rgbaRow1, tmpRgbSpan, width); + AccumulateRgb(bgraRow0, bgraRow1, tmpRgbSpan, width); } else { - AccumulateRgba(rgbaRow0, rgbaRow1, tmpRgbSpan, width); + AccumulateRgba(bgraRow0, bgraRow1, tmpRgbSpan, width); } ConvertRgbaToUv(tmpRgbSpan, u.Slice(uvRowIndex * uvWidth), v.Slice(uvRowIndex * uvWidth), uvWidth); uvRowIndex++; - ConvertRgbaToY(rgbaRow0, y.Slice(rowIndex * width), width); - ConvertRgbaToY(rgbaRow1, y.Slice((rowIndex + 1) * width), width); + ConvertRgbaToY(bgraRow0, y.Slice(rowIndex * width), width); + ConvertRgbaToY(bgraRow1, y.Slice((rowIndex + 1) * width), width); } // Extra last row. if ((height & 1) != 0) { Span rowSpan = image.GetPixelRowSpan(rowIndex); - PixelOperations.Instance.ToRgba32(configuration, rowSpan, rgbaRow0); - ConvertRgbaToY(rgbaRow0, y.Slice(rowIndex * width), width); + PixelOperations.Instance.ToBgra32(configuration, rowSpan, bgraRow0); + ConvertRgbaToY(bgraRow0, y.Slice(rowIndex * width), width); - if (!CheckNonOpaque(rgbaRow0)) + if (!WebpCommonUtils.CheckNonOpaque(bgraRow0)) { - AccumulateRgb(rgbaRow0, rgbaRow0, tmpRgbSpan, width); + AccumulateRgb(bgraRow0, bgraRow0, tmpRgbSpan, width); } else { - AccumulateRgba(rgbaRow0, rgbaRow0, tmpRgbSpan, width); + AccumulateRgba(bgraRow0, bgraRow0, tmpRgbSpan, width); } ConvertRgbaToUv(tmpRgbSpan, u.Slice(uvRowIndex * uvWidth), v.Slice(uvRowIndex * uvWidth), uvWidth); } } - /// - /// Checks if the pixel row is not opaque. - /// - /// The row to check. - /// Returns true if alpha has non-0xff values. - public static unsafe bool CheckNonOpaque(Span row) - { -#if SUPPORTS_RUNTIME_INTRINSICS - if (Avx2.IsSupported) - { - ReadOnlySpan rowBytes = MemoryMarshal.AsBytes(row); - var alphaMaskVector256 = Vector256.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); - Vector256 all0x80Vector256 = Vector256.Create((byte)0x80).AsByte(); - var alphaMask = Vector128.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); - Vector128 all0x80 = Vector128.Create((byte)0x80).AsByte(); - - int i = 0; - int length = (row.Length * 4) - 3; - fixed (byte* src = rowBytes) - { - for (; i + 128 <= length; i += 128) - { - Vector256 a0 = Avx.LoadVector256(src + i).AsByte(); - Vector256 a1 = Avx.LoadVector256(src + i + 32).AsByte(); - Vector256 a2 = Avx.LoadVector256(src + i + 64).AsByte(); - Vector256 a3 = Avx.LoadVector256(src + i + 96).AsByte(); - Vector256 b0 = Avx2.And(a0, alphaMaskVector256).AsInt32(); - Vector256 b1 = Avx2.And(a1, alphaMaskVector256).AsInt32(); - Vector256 b2 = Avx2.And(a2, alphaMaskVector256).AsInt32(); - Vector256 b3 = Avx2.And(a3, alphaMaskVector256).AsInt32(); - Vector256 c0 = Avx2.PackSignedSaturate(b0, b1).AsInt16(); - Vector256 c1 = Avx2.PackSignedSaturate(b2, b3).AsInt16(); - Vector256 d = Avx2.PackSignedSaturate(c0, c1).AsByte(); - Vector256 bits = Avx2.CompareEqual(d, all0x80Vector256); - int mask = Avx2.MoveMask(bits); - if (mask != -1) - { - return true; - } - } - - for (; i + 64 <= length; i += 64) - { - if (IsNoneOpaque64Bytes(src, i, alphaMask, all0x80)) - { - return true; - } - } - - for (; i + 32 <= length; i += 32) - { - if (IsNoneOpaque32Bytes(src, i, alphaMask, all0x80)) - { - return true; - } - } - - for (; i <= length; i += 4) - { - if (src[i + 3] != 0xFF) - { - return true; - } - } - } - } - else if (Sse2.IsSupported) - { - ReadOnlySpan rowBytes = MemoryMarshal.AsBytes(row); - var alphaMask = Vector128.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); - Vector128 all0x80 = Vector128.Create((byte)0x80).AsByte(); - - int i = 0; - int length = (row.Length * 4) - 3; - fixed (byte* src = rowBytes) - { - for (; i + 64 <= length; i += 64) - { - if (IsNoneOpaque64Bytes(src, i, alphaMask, all0x80)) - { - return true; - } - } - - for (; i + 32 <= length; i += 32) - { - if (IsNoneOpaque32Bytes(src, i, alphaMask, all0x80)) - { - return true; - } - } - - for (; i <= length; i += 4) - { - if (src[i + 3] != 0xFF) - { - return true; - } - } - } - } - else -#endif - { - for (int x = 0; x < row.Length; x++) - { - if (row[x].A != 0xFF) - { - return true; - } - } - } - - return false; - } - -#if SUPPORTS_RUNTIME_INTRINSICS - private static unsafe bool IsNoneOpaque64Bytes(byte* src, int i, Vector128 alphaMask, Vector128 all0x80) - { - Vector128 a0 = Sse2.LoadVector128(src + i).AsByte(); - Vector128 a1 = Sse2.LoadVector128(src + i + 16).AsByte(); - Vector128 a2 = Sse2.LoadVector128(src + i + 32).AsByte(); - Vector128 a3 = Sse2.LoadVector128(src + i + 48).AsByte(); - Vector128 b0 = Sse2.And(a0, alphaMask).AsInt32(); - Vector128 b1 = Sse2.And(a1, alphaMask).AsInt32(); - Vector128 b2 = Sse2.And(a2, alphaMask).AsInt32(); - Vector128 b3 = Sse2.And(a3, alphaMask).AsInt32(); - Vector128 c0 = Sse2.PackSignedSaturate(b0, b1).AsInt16(); - Vector128 c1 = Sse2.PackSignedSaturate(b2, b3).AsInt16(); - Vector128 d = Sse2.PackSignedSaturate(c0, c1).AsByte(); - Vector128 bits = Sse2.CompareEqual(d, all0x80); - int mask = Sse2.MoveMask(bits); - if (mask != 0xFFFF) - { - return true; - } - - return false; - } - - private static unsafe bool IsNoneOpaque32Bytes(byte* src, int i, Vector128 alphaMask, Vector128 all0x80) - { - Vector128 a0 = Sse2.LoadVector128(src + i).AsByte(); - Vector128 a1 = Sse2.LoadVector128(src + i + 16).AsByte(); - Vector128 b0 = Sse2.And(a0, alphaMask).AsInt32(); - Vector128 b1 = Sse2.And(a1, alphaMask).AsInt32(); - Vector128 c = Sse2.PackSignedSaturate(b0, b1).AsInt16(); - Vector128 d = Sse2.PackSignedSaturate(c, c).AsByte(); - Vector128 bits = Sse2.CompareEqual(d, all0x80); - int mask = Sse2.MoveMask(bits); - if (mask != 0xFFFF) - { - return true; - } - - return false; - } -#endif - /// /// Converts a rgba pixel row to Y. /// @@ -262,7 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy /// The destination span for y. /// The width. [MethodImpl(InliningOptions.ShortMethod)] - public static void ConvertRgbaToY(Span rowSpan, Span y, int width) + public static void ConvertRgbaToY(Span rowSpan, Span y, int width) { for (int x = 0; x < width; x++) { @@ -288,84 +123,84 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy } } - public static void AccumulateRgb(Span rowSpan, Span nextRowSpan, Span dst, int width) + public static void AccumulateRgb(Span rowSpan, Span nextRowSpan, Span dst, int width) { - Rgba32 rgba0; - Rgba32 rgba1; + Bgra32 bgra0; + Bgra32 bgra1; int i, j; int dstIdx = 0; for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2, dstIdx += 4) { - rgba0 = rowSpan[j]; - rgba1 = rowSpan[j + 1]; - Rgba32 rgba2 = nextRowSpan[j]; - Rgba32 rgba3 = nextRowSpan[j + 1]; + bgra0 = rowSpan[j]; + bgra1 = rowSpan[j + 1]; + Bgra32 bgra2 = nextRowSpan[j]; + Bgra32 bgra3 = nextRowSpan[j + 1]; dst[dstIdx] = (ushort)LinearToGamma( - GammaToLinear(rgba0.R) + - GammaToLinear(rgba1.R) + - GammaToLinear(rgba2.R) + - GammaToLinear(rgba3.R), 0); + GammaToLinear(bgra0.R) + + GammaToLinear(bgra1.R) + + GammaToLinear(bgra2.R) + + GammaToLinear(bgra3.R), 0); dst[dstIdx + 1] = (ushort)LinearToGamma( - GammaToLinear(rgba0.G) + - GammaToLinear(rgba1.G) + - GammaToLinear(rgba2.G) + - GammaToLinear(rgba3.G), 0); + GammaToLinear(bgra0.G) + + GammaToLinear(bgra1.G) + + GammaToLinear(bgra2.G) + + GammaToLinear(bgra3.G), 0); dst[dstIdx + 2] = (ushort)LinearToGamma( - GammaToLinear(rgba0.B) + - GammaToLinear(rgba1.B) + - GammaToLinear(rgba2.B) + - GammaToLinear(rgba3.B), 0); + GammaToLinear(bgra0.B) + + GammaToLinear(bgra1.B) + + GammaToLinear(bgra2.B) + + GammaToLinear(bgra3.B), 0); } if ((width & 1) != 0) { - rgba0 = rowSpan[j]; - rgba1 = nextRowSpan[j]; + bgra0 = rowSpan[j]; + bgra1 = nextRowSpan[j]; - dst[dstIdx] = (ushort)LinearToGamma(GammaToLinear(rgba0.R) + GammaToLinear(rgba1.R), 1); - dst[dstIdx + 1] = (ushort)LinearToGamma(GammaToLinear(rgba0.G) + GammaToLinear(rgba1.G), 1); - dst[dstIdx + 2] = (ushort)LinearToGamma(GammaToLinear(rgba0.B) + GammaToLinear(rgba1.B), 1); + dst[dstIdx] = (ushort)LinearToGamma(GammaToLinear(bgra0.R) + GammaToLinear(bgra1.R), 1); + dst[dstIdx + 1] = (ushort)LinearToGamma(GammaToLinear(bgra0.G) + GammaToLinear(bgra1.G), 1); + dst[dstIdx + 2] = (ushort)LinearToGamma(GammaToLinear(bgra0.B) + GammaToLinear(bgra1.B), 1); } } - public static void AccumulateRgba(Span rowSpan, Span nextRowSpan, Span dst, int width) + public static void AccumulateRgba(Span rowSpan, Span nextRowSpan, Span dst, int width) { - Rgba32 rgba0; - Rgba32 rgba1; + Bgra32 bgra0; + Bgra32 bgra1; int i, j; int dstIdx = 0; for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2, dstIdx += 4) { - rgba0 = rowSpan[j]; - rgba1 = rowSpan[j + 1]; - Rgba32 rgba2 = nextRowSpan[j]; - Rgba32 rgba3 = nextRowSpan[j + 1]; - uint a = (uint)(rgba0.A + rgba1.A + rgba2.A + rgba3.A); + bgra0 = rowSpan[j]; + bgra1 = rowSpan[j + 1]; + Bgra32 bgra2 = nextRowSpan[j]; + Bgra32 bgra3 = nextRowSpan[j + 1]; + uint a = (uint)(bgra0.A + bgra1.A + bgra2.A + bgra3.A); int r, g, b; if (a == 4 * 0xff || a == 0) { r = (ushort)LinearToGamma( - GammaToLinear(rgba0.R) + - GammaToLinear(rgba1.R) + - GammaToLinear(rgba2.R) + - GammaToLinear(rgba3.R), 0); + GammaToLinear(bgra0.R) + + GammaToLinear(bgra1.R) + + GammaToLinear(bgra2.R) + + GammaToLinear(bgra3.R), 0); g = (ushort)LinearToGamma( - GammaToLinear(rgba0.G) + - GammaToLinear(rgba1.G) + - GammaToLinear(rgba2.G) + - GammaToLinear(rgba3.G), 0); + GammaToLinear(bgra0.G) + + GammaToLinear(bgra1.G) + + GammaToLinear(bgra2.G) + + GammaToLinear(bgra3.G), 0); b = (ushort)LinearToGamma( - GammaToLinear(rgba0.B) + - GammaToLinear(rgba1.B) + - GammaToLinear(rgba2.B) + - GammaToLinear(rgba3.B), 0); + GammaToLinear(bgra0.B) + + GammaToLinear(bgra1.B) + + GammaToLinear(bgra2.B) + + GammaToLinear(bgra3.B), 0); } else { - r = LinearToGammaWeighted(rgba0.R, rgba1.R, rgba2.R, rgba3.R, rgba0.A, rgba1.A, rgba2.A, rgba3.A, a); - g = LinearToGammaWeighted(rgba0.G, rgba1.G, rgba2.G, rgba3.G, rgba0.A, rgba1.A, rgba2.A, rgba3.A, a); - b = LinearToGammaWeighted(rgba0.B, rgba1.B, rgba2.B, rgba3.B, rgba0.A, rgba1.A, rgba2.A, rgba3.A, a); + r = LinearToGammaWeighted(bgra0.R, bgra1.R, bgra2.R, bgra3.R, bgra0.A, bgra1.A, bgra2.A, bgra3.A, a); + g = LinearToGammaWeighted(bgra0.G, bgra1.G, bgra2.G, bgra3.G, bgra0.A, bgra1.A, bgra2.A, bgra3.A, a); + b = LinearToGammaWeighted(bgra0.B, bgra1.B, bgra2.B, bgra3.B, bgra0.A, bgra1.A, bgra2.A, bgra3.A, a); } dst[dstIdx] = (ushort)r; @@ -376,21 +211,21 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy if ((width & 1) != 0) { - rgba0 = rowSpan[j]; - rgba1 = nextRowSpan[j]; - uint a = (uint)(2u * (rgba0.A + rgba1.A)); + bgra0 = rowSpan[j]; + bgra1 = nextRowSpan[j]; + uint a = (uint)(2u * (bgra0.A + bgra1.A)); int r, g, b; if (a == 4 * 0xff || a == 0) { - r = (ushort)LinearToGamma(GammaToLinear(rgba0.R) + GammaToLinear(rgba1.R), 1); - g = (ushort)LinearToGamma(GammaToLinear(rgba0.G) + GammaToLinear(rgba1.G), 1); - b = (ushort)LinearToGamma(GammaToLinear(rgba0.B) + GammaToLinear(rgba1.B), 1); + r = (ushort)LinearToGamma(GammaToLinear(bgra0.R) + GammaToLinear(bgra1.R), 1); + g = (ushort)LinearToGamma(GammaToLinear(bgra0.G) + GammaToLinear(bgra1.G), 1); + b = (ushort)LinearToGamma(GammaToLinear(bgra0.B) + GammaToLinear(bgra1.B), 1); } else { - r = LinearToGammaWeighted(rgba0.R, rgba1.R, rgba0.R, rgba1.R, rgba0.A, rgba1.A, rgba0.A, rgba1.A, a); - g = LinearToGammaWeighted(rgba0.G, rgba1.G, rgba0.G, rgba1.G, rgba0.A, rgba1.A, rgba0.A, rgba1.A, a); - b = LinearToGammaWeighted(rgba0.B, rgba1.B, rgba0.B, rgba1.B, rgba0.A, rgba1.A, rgba0.A, rgba1.A, a); + r = LinearToGammaWeighted(bgra0.R, bgra1.R, bgra0.R, bgra1.R, bgra0.A, bgra1.A, bgra0.A, bgra1.A, a); + g = LinearToGammaWeighted(bgra0.G, bgra1.G, bgra0.G, bgra1.G, bgra0.A, bgra1.A, bgra0.A, bgra1.A, a); + b = LinearToGammaWeighted(bgra0.B, bgra1.B, bgra0.B, bgra1.B, bgra0.A, bgra1.A, bgra0.A, bgra1.A, a); } dst[dstIdx] = (ushort)r; diff --git a/src/ImageSharp/Formats/WebP/WebpCommonUtils.cs b/src/ImageSharp/Formats/WebP/WebpCommonUtils.cs index 82af88d675..cdd324b07e 100644 --- a/src/ImageSharp/Formats/WebP/WebpCommonUtils.cs +++ b/src/ImageSharp/Formats/WebP/WebpCommonUtils.cs @@ -1,8 +1,14 @@ // Copyright (c) Six Labors. // Licensed under the Apache License, Version 2.0. +using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif namespace SixLabors.ImageSharp.Formats.Webp { @@ -26,5 +32,164 @@ namespace SixLabors.ImageSharp.Formats.Webp return logValue + Unsafe.Add(ref MemoryMarshal.GetReference(WebpLookupTables.LogTable8Bit), (int)n); } + + /// + /// Checks if the pixel row is not opaque. + /// + /// The row to check. + /// Returns true if alpha has non-0xff values. + public static unsafe bool CheckNonOpaque(Span row) + { +#if SUPPORTS_RUNTIME_INTRINSICS + if (Avx2.IsSupported) + { + ReadOnlySpan rowBytes = MemoryMarshal.AsBytes(row); + var alphaMaskVector256 = Vector256.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); + Vector256 all0x80Vector256 = Vector256.Create((byte)0x80).AsByte(); + var alphaMask = Vector128.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); + Vector128 all0x80 = Vector128.Create((byte)0x80).AsByte(); + + int i = 0; + int length = (row.Length * 4) - 3; + fixed (byte* src = rowBytes) + { + for (; i + 128 <= length; i += 128) + { + Vector256 a0 = Avx.LoadVector256(src + i).AsByte(); + Vector256 a1 = Avx.LoadVector256(src + i + 32).AsByte(); + Vector256 a2 = Avx.LoadVector256(src + i + 64).AsByte(); + Vector256 a3 = Avx.LoadVector256(src + i + 96).AsByte(); + Vector256 b0 = Avx2.And(a0, alphaMaskVector256).AsInt32(); + Vector256 b1 = Avx2.And(a1, alphaMaskVector256).AsInt32(); + Vector256 b2 = Avx2.And(a2, alphaMaskVector256).AsInt32(); + Vector256 b3 = Avx2.And(a3, alphaMaskVector256).AsInt32(); + Vector256 c0 = Avx2.PackSignedSaturate(b0, b1).AsInt16(); + Vector256 c1 = Avx2.PackSignedSaturate(b2, b3).AsInt16(); + Vector256 d = Avx2.PackSignedSaturate(c0, c1).AsByte(); + Vector256 bits = Avx2.CompareEqual(d, all0x80Vector256); + int mask = Avx2.MoveMask(bits); + if (mask != -1) + { + return true; + } + } + + for (; i + 64 <= length; i += 64) + { + if (IsNoneOpaque64Bytes(src, i, alphaMask, all0x80)) + { + return true; + } + } + + for (; i + 32 <= length; i += 32) + { + if (IsNoneOpaque32Bytes(src, i, alphaMask, all0x80)) + { + return true; + } + } + + for (; i <= length; i += 4) + { + if (src[i + 3] != 0xFF) + { + return true; + } + } + } + } + else if (Sse2.IsSupported) + { + ReadOnlySpan rowBytes = MemoryMarshal.AsBytes(row); + var alphaMask = Vector128.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); + Vector128 all0x80 = Vector128.Create((byte)0x80).AsByte(); + + int i = 0; + int length = (row.Length * 4) - 3; + fixed (byte* src = rowBytes) + { + for (; i + 64 <= length; i += 64) + { + if (IsNoneOpaque64Bytes(src, i, alphaMask, all0x80)) + { + return true; + } + } + + for (; i + 32 <= length; i += 32) + { + if (IsNoneOpaque32Bytes(src, i, alphaMask, all0x80)) + { + return true; + } + } + + for (; i <= length; i += 4) + { + if (src[i + 3] != 0xFF) + { + return true; + } + } + } + } + else +#endif + { + for (int x = 0; x < row.Length; x++) + { + if (row[x].A != 0xFF) + { + return true; + } + } + } + + return false; + } + +#if SUPPORTS_RUNTIME_INTRINSICS + private static unsafe bool IsNoneOpaque64Bytes(byte* src, int i, Vector128 alphaMask, Vector128 all0x80) + { + Vector128 a0 = Sse2.LoadVector128(src + i).AsByte(); + Vector128 a1 = Sse2.LoadVector128(src + i + 16).AsByte(); + Vector128 a2 = Sse2.LoadVector128(src + i + 32).AsByte(); + Vector128 a3 = Sse2.LoadVector128(src + i + 48).AsByte(); + Vector128 b0 = Sse2.And(a0, alphaMask).AsInt32(); + Vector128 b1 = Sse2.And(a1, alphaMask).AsInt32(); + Vector128 b2 = Sse2.And(a2, alphaMask).AsInt32(); + Vector128 b3 = Sse2.And(a3, alphaMask).AsInt32(); + Vector128 c0 = Sse2.PackSignedSaturate(b0, b1).AsInt16(); + Vector128 c1 = Sse2.PackSignedSaturate(b2, b3).AsInt16(); + Vector128 d = Sse2.PackSignedSaturate(c0, c1).AsByte(); + Vector128 bits = Sse2.CompareEqual(d, all0x80); + int mask = Sse2.MoveMask(bits); + if (mask != 0xFFFF) + { + return true; + } + + return false; + } + + private static unsafe bool IsNoneOpaque32Bytes(byte* src, int i, Vector128 alphaMask, Vector128 all0x80) + { + Vector128 a0 = Sse2.LoadVector128(src + i).AsByte(); + Vector128 a1 = Sse2.LoadVector128(src + i + 16).AsByte(); + Vector128 b0 = Sse2.And(a0, alphaMask).AsInt32(); + Vector128 b1 = Sse2.And(a1, alphaMask).AsInt32(); + Vector128 c = Sse2.PackSignedSaturate(b0, b1).AsInt16(); + Vector128 d = Sse2.PackSignedSaturate(c, c).AsByte(); + Vector128 bits = Sse2.CompareEqual(d, all0x80); + int mask = Sse2.MoveMask(bits); + if (mask != 0xFFFF) + { + return true; + } + + return false; + } +#endif } } diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs new file mode 100644 index 0000000000..71bd5bf8d2 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs @@ -0,0 +1,214 @@ +// Copyright (c) Six Labors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats.Webp; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +#if SUPPORTS_RUNTIME_INTRINSICS +using SixLabors.ImageSharp.Tests.TestUtilities; +#endif + +namespace SixLabors.ImageSharp.Tests.Formats.Webp +{ + [Trait("Format", "Webp")] + public class WebpCommonUtilsTests + { + [Fact] + public void CheckNonOpaque_WithOpaquePixels_Works() => RunCheckNoneOpaqueWithOpaquePixelsTest(); + + [Fact] + public void CheckNonOpaque_WithNoneOpaquePixels_Works() => RunCheckNoneOpaqueWithNoneOpaquePixelsTest(); + +#if SUPPORTS_RUNTIME_INTRINSICS + [Fact] + public void CheckNonOpaque_WithOpaquePixels_WithHardwareIntrinsics_Works() + => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithOpaquePixelsTest, HwIntrinsics.AllowAll); + + [Fact] + public void CheckNonOpaque_WithOpaquePixels_WithoutSse2_Works() + => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithOpaquePixelsTest, HwIntrinsics.DisableSSE2); + + [Fact] + public void CheckNonOpaque_WithOpaquePixels_WithoutAvx2_Works() + => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithOpaquePixelsTest, HwIntrinsics.DisableAVX2); + + [Fact] + public void CheckNonOpaque_WithNoneOpaquePixels_WithHardwareIntrinsics_Works() + => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithNoneOpaquePixelsTest, HwIntrinsics.AllowAll); + + [Fact] + public void CheckNonOpaque_WithNoneOpaquePixels_WithoutSse2_Works() + => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithNoneOpaquePixelsTest, HwIntrinsics.DisableSSE2); + + [Fact] + public void CheckNonOpaque_WithNoneOpaquePixels_WithoutAvx2_Works() + => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithNoneOpaquePixelsTest, HwIntrinsics.DisableAVX2); +#endif + + private static void RunCheckNoneOpaqueWithNoneOpaquePixelsTest() + { + // arrange + byte[] rowBytes = + { + 122, 120, 101, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 122, 120, 101, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 148, 158, 158, 10, + 171, 165, 151, 255, + 209, 208, 210, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 10, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 209, 208, 210, 0, + 174, 183, 189, 255, + 148, 158, 158, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 0, + 148, 158, 158, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 148, 158, 158, 100, + 171, 165, 151, 0, + 209, 208, 210, 100, + 174, 183, 189, 255, + 148, 158, 158, 255, + }; + Span row = MemoryMarshal.Cast(rowBytes); + + bool noneOpaque; + for (int length = 8; length < row.Length; length += 8) + { + // act + noneOpaque = WebpCommonUtils.CheckNonOpaque(row); + + // assert + Assert.True(noneOpaque); + } + + // One last test with the complete row. + noneOpaque = WebpCommonUtils.CheckNonOpaque(row); + Assert.True(noneOpaque); + } + + private static void RunCheckNoneOpaqueWithOpaquePixelsTest() + { + // arrange + byte[] rowBytes = + { + 122, 120, 101, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 122, 120, 101, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + 148, 158, 158, 255, + 171, 165, 151, 255, + 209, 208, 210, 255, + 174, 183, 189, 255, + 148, 158, 158, 255, + }; + Span row = MemoryMarshal.Cast(rowBytes); + + bool noneOpaque; + for (int length = 8; length < row.Length; length += 8) + { + // act + noneOpaque = WebpCommonUtils.CheckNonOpaque(row.Slice(0, length)); + + // assert + Assert.False(noneOpaque); + } + + // One last test with the complete row. + noneOpaque = WebpCommonUtils.CheckNonOpaque(row); + Assert.False(noneOpaque); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index 0bf4b5dcf2..33f7930d16 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -203,6 +203,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp } } + [Theory] + [WithFile(Lossless.Alpha, PixelTypes.Rgba32)] + public void WebpDecoder_CanDecode_Lossless_WithAlpha(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(WebpDecoder)) + { + image.DebugSave(provider); + image.CompareToOriginal(provider, ReferenceDecoder); + } + } + [Theory] [WithFile(Lossless.NoTransform1, PixelTypes.Rgba32)] [WithFile(Lossless.NoTransform2, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs index 4392954060..0e2a5c13ab 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs @@ -2,53 +2,17 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using Xunit; -#if SUPPORTS_RUNTIME_INTRINSICS -using SixLabors.ImageSharp.Tests.TestUtilities; -#endif namespace SixLabors.ImageSharp.Tests.Formats.Webp { [Trait("Format", "Webp")] public class YuvConversionTests { - [Fact] - public void CheckNonOpaque_WithOpaquePixels_Works() => RunCheckNoneOpaqueWithOpaquePixelsTest(); - - [Fact] - public void CheckNonOpaque_WithNoneOpaquePixels_Works() => RunCheckNoneOpaqueWithNoneOpaquePixelsTest(); - -#if SUPPORTS_RUNTIME_INTRINSICS - [Fact] - public void CheckNonOpaque_WithOpaquePixels_WithHardwareIntrinsics_Works() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithOpaquePixelsTest, HwIntrinsics.AllowAll); - - [Fact] - public void CheckNonOpaque_WithOpaquePixels_WithoutSse2_Works() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithOpaquePixelsTest, HwIntrinsics.DisableSSE2); - - [Fact] - public void CheckNonOpaque_WithOpaquePixels_WithoutAvx2_Works() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithOpaquePixelsTest, HwIntrinsics.DisableAVX2); - - [Fact] - public void CheckNonOpaque_WithNoneOpaquePixels_WithHardwareIntrinsics_Works() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithNoneOpaquePixelsTest, HwIntrinsics.AllowAll); - - [Fact] - public void CheckNonOpaque_WithNoneOpaquePixels_WithoutSse2_Works() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithNoneOpaquePixelsTest, HwIntrinsics.DisableSSE2); - - [Fact] - public void CheckNonOpaque_WithNoneOpaquePixels_WithoutAvx2_Works() - => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCheckNoneOpaqueWithNoneOpaquePixelsTest, HwIntrinsics.DisableAVX2); -#endif - [Theory] [WithFile(TestImages.WebP.Yuv, PixelTypes.Rgba32)] public void ConvertRgbToYuv_Works(TestImageProvider provider) @@ -167,7 +131,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp [Theory] [WithTestPatternImages(31, 31, PixelTypes.Rgba32)] - public void ConvertRgbToYuv_WithAlpha_Works(TestImageProvider provider) + public void ConvertRgbToYuv_WithTestPattern_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel { // arrange @@ -270,168 +234,304 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp Assert.True(expectedV.AsSpan().SequenceEqual(v.Slice(0, expectedV.Length))); } - private static void RunCheckNoneOpaqueWithNoneOpaquePixelsTest() + [Theory] + [WithFile(TestImages.WebP.Lossless.Alpha, PixelTypes.Rgba32)] + public void ConvertRgbToYuv_WithAlphaImage_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel { // arrange - byte[] rowBytes = + using Image image = provider.GetImage(); + Configuration config = image.GetConfiguration(); + MemoryAllocator memoryAllocator = config.MemoryAllocator; + int pixels = image.Width * image.Height; + int uvWidth = (image.Width + 1) >> 1; + using System.Buffers.IMemoryOwner yBuffer = memoryAllocator.Allocate(pixels); + using System.Buffers.IMemoryOwner uBuffer = memoryAllocator.Allocate(uvWidth * image.Height); + using System.Buffers.IMemoryOwner vBuffer = memoryAllocator.Allocate(uvWidth * image.Height); + Span y = yBuffer.GetSpan(); + Span u = uBuffer.GetSpan(); + Span v = vBuffer.GetSpan(); + byte[] expectedY = { - 122, 120, 101, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 122, 120, 101, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 148, 158, 158, 10, - 171, 165, 151, 255, - 209, 208, 210, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 10, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 209, 208, 210, 0, - 174, 183, 189, 255, - 148, 158, 158, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 0, - 148, 158, 158, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 148, 158, 158, 100, - 171, 165, 151, 0, - 209, 208, 210, 100, - 174, 183, 189, 255, - 148, 158, 158, 255, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 108, 106, 113, 110, 111, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 105, 100, 95, 105, 92, 126, + 130, 130, 130, 130, 130, 126, 108, 112, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 155, 123, 107, + 140, 126, 122, 123, 123, 123, 123, 123, 119, 57, 107, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, + 127, 116, 142, 159, 156, 154, 155, 155, 154, 154, 154, 152, 132, 79, 33, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 17, 157, 132, 158, 158, 159, 157, 148, 146, 154, 159, 159, 160, 149, 109, 57, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 17, 160, 133, 158, 159, 156, 133, 101, 88, 122, 150, 159, 159, 150, 110, 57, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 160, 133, 158, 159, 145, 83, 115, 108, 164, 132, 158, 159, + 150, 110, 58, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 161, 134, 158, 159, 140, 210, 96, 109, 134, + 127, 156, 159, 150, 111, 58, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 161, 134, 158, 159, 146, 96, + 123, 117, 211, 135, 158, 159, 150, 111, 58, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 163, 134, 158, + 158, 158, 139, 116, 110, 129, 153, 159, 159, 150, 111, 58, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, + 142, 126, 154, 160, 159, 159, 153, 151, 158, 160, 159, 160, 143, 101, 48, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 101, 27, 130, 144, 145, 145, 145, 145, 145, 145, 145, 140, 116, 129, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 112, 103, 41, 83, 84, 84, 84, 84, 84, 84, 85, 73, 129, 41, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 104, 107, 107, 109, 109, 109, 109, 109, 109, 109, 109, 108, 100, + 106, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; - Span row = MemoryMarshal.Cast(rowBytes); - - bool noneOpaque; - for (int length = 8; length < row.Length; length += 8) - { - // act - noneOpaque = YuvConversion.CheckNonOpaque(row); - - // assert - Assert.True(noneOpaque); - } - - // One last test with the complete row. - noneOpaque = YuvConversion.CheckNonOpaque(row); - Assert.True(noneOpaque); - } - - private static void RunCheckNoneOpaqueWithOpaquePixelsTest() - { - // arrange - byte[] rowBytes = + byte[] expectedU = { - 122, 120, 101, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 122, 120, 101, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, - 148, 158, 158, 255, - 171, 165, 151, 255, - 209, 208, 210, 255, - 174, 183, 189, 255, - 148, 158, 158, 255, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 125, 120, 112, 106, 112, 112, 116, + 124, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 108, 90, 78, 79, 79, 79, 84, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 103, 77, 70, 79, 81, 70, 72, 105, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 102, 77, 75, 125, 91, 78, 72, 105, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 102, 77, 72, 92, 94, 74, 72, 105, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 115, + 84, 74, 75, 76, 74, 79, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 120, 240, 124, 123, 123, 123, 132, 148, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 110, 226, 185, 225, 56, + 48, 209, 111, 254, 56, 74, 116, 56, 222, 107, 255, 163, 237, 83, 1, 99, 241, 23, 1, 128, 186, 211, + 52, 84, 206, 135, 202, 159, 178, 4, 118, 130, 203, 127, 164, 82, 203, 119, 36, 123, 187, 82, 188, + 237, 245, 42, 15, 46, 92, 94, 191, 244, 175, 146, 126, 163, 13, 56, 67, 113, 84, 4, 48, 70, 9, 5, + 207, 208, 212, 229, 220, 34, 75, 138, 148, 253, 173, 238, 137, 121, 176, 79, 36, 185, 51, 17, 150, + 194, 218, 92, 83, 147, 117, 107, 59, 202, 241, 94, 251, 31, 109, 159, 10, 24, 139, 127, 208, 0, 95, + 128, 236, 27, 97, 149, 231, 77, 79, 253, 9, 154, 137, 50, 187, 183, 43, 234, 147, 85, 145, 3, 54, + 146, 151, 7, 255, 131, 208, 141, 202, 155, 31, 254, 95, 68, 71, 9, 5, 255, 83, 83, 151, 119, 75, 44, + 41, 226, 40, 81, 71, 117, 56, 92, 255, 7, 151, 187, 35, 145, 214, 74, 125, 222, 81, 146, 136, 131, + 119, 202, 241, 126, 251, 31, 109, 175, 5, 2, 174, 0, 233, 55, 60, 171, 54, 22, 21, 27, 132, 254, + 150, 200, 193, 119, 87, 47, 207, 78, 57, 129, 190, 13, 255, 69, 131, 40, 113, 71, 241, 47, 178, 195, + 184, 27, 45, 55, 208, 156, 22, 1, 140, 210, 148, 67, 237, 238, 195, 245, 118, 157, 149, 23, 14, 164, + 122, 19, 235, 95, 111, 52, 22, 198, 61, 182, 20, 113, 148, 72, 8, 224, 83, 113, 35, 180, 242, 178, + 33, 247, 179, 52, 208, 169, 136, 108, 90, 203, 250, 235, 222, 75, 22, 176, 13, 237, 215, 21, 205, + 61, 209, 139, 53, 112, 39, 244, 158, 138, 0, 250, 40, 161, 88, 157, 107, 234, 242, 110, 245, 226, + 130, 37, 141, 218, 42, 195, 81, 178, 39, 55, 68, 219, 75, 89, 69, 202, 79, 207, 140, 172, 56, 74, + 116, 56, 209, 111, 21, 227, 168, 69, 38, 75, 127, 208, 8, 160, 234, 70, 93, 245, 230, 54, 109, 245, + 166, 225, 114, 6, 99, 99, 93, 254, 106, 175, 136, 93, 32, 216, 168, 20, 220, 97, 120, 95, 32, 228, + 27, 31, 120, 78, 220, 43, 2, 40, 161, 132, 162, 187, 222, 83, 20, 79, 67, 179, 99, 43, 158, 214, 82, + 42, 239, 167, 6, 141, 142, 247, 148, 92, 45, 234, 105, 244, 175, 190, 207, 235, 76, 163, 133, 47, 4, + 0, 38, 79, 8, 220, 85, 58, 182, 49, 234, 168, 102, 27, 198, 183, 186, 218, 251, 215, 101, 194, 43, + 191, 48, 157, 112, 185, 40, 42, 55, 25, 135, 114, 1, 253, 82, 1, 206, 0, 86, 169, 239, 211, 26, 152, + 254, 205, 149, 233, 48, 223, 215, 234, 95, 251, 91, 253, 125, 127, 171, 187, 31, 104, 119, 15, 87, + 31, 255, 253, 173, 238, 177, 163, 58, 92, 38, 123, 114, 85, 69, 202, 35, 21, 240, 69, 252, 32, 165, + 138, 233, 54, 196, 190, 29, 152, 108, 155, 217, 131, 164, 29, 145, 184, 173, 172, 128, 182, 129, + 127, 221, 239, 10, 239, 93, 102, 254, 137, 244, 69, 250, 95, 86, 1, 250, 1, 72, 227, 28, 19, 1, 47, + 107, 192, 211, 192, 60, 218, 135, 205, 143, 118, 33, 129, 22, 199, 187, 176, 233, 250, 217, 91, 145, + 114, 128, 39, 130, 200, 143, 44, 224, 66, 64, 33, 181, 202, 14, 244, 109, 83, 119, 241, 23, 245, 69, + 196, 225, 173, 211, 104, 148, 207, 252, 209, 40, 230, 103, 235, 85, 138, 182, 205, 104, 229, 176, + 242, 243, 223, 93, 77, 1, 172, 82, 169, 255, 219, 141, 80, 203, 76, 232, 199, 154, 8, 219, 68, 132, + 173, 32, 56, 220, 90, 241, 122, 184, 16, 252, 190, 70, 192, 222, 118, 61, 111, 239, 223, 93, 169, + 239, 74, 254, 162, 99, 87, 28, 23, 243, 96, 110, 246, 191, 23, 123, 160, 226, 247, 47, 186, 42, 38, + 34, 187, 181, 246, 158, 84, 130, 52, 192, 1, 160, 209, 83, 183, 124, 118, 86, 89, 239, 226, 59, 76, + 102, 249, 79, 122, 15, 68, 39, 235, 203, 195, 187, 250, 41, 2, 71, 250, 229, 8, 241, 152, 189, 116, + 241, 32, 25, 246, 36, 117, 34, 197, 111, 249, 240, 2, 213, 221, 130, 39, 255, 143, 223, 118, 254, + 153, 212, 63, 64 }; - Span row = MemoryMarshal.Cast(rowBytes); - - bool noneOpaque; - for (int length = 8; length < row.Length; length += 8) + byte[] expectedV = { - // act - noneOpaque = YuvConversion.CheckNonOpaque(row.Slice(0, length)); + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 127, 127, 126, 126, 126, 127, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 126, 123, 122, 122, 123, 122, 123, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 125, 122, 121, 122, 122, 121, 122, + 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 125, 122, 122, 128, 124, 122, 121, 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 125, 122, 121, 124, 124, 122, 122, + 125, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 126, 123, 122, 122, 122, 122, 123, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 127, 110, 129, 129, 129, 129, 130, + 124, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; - // assert - Assert.False(noneOpaque); - } + // act + YuvConversion.ConvertRgbToYuv(image, config, memoryAllocator, y, u, v); - // One last test with the complete row. - noneOpaque = YuvConversion.CheckNonOpaque(row); - Assert.False(noneOpaque); + // assert + Assert.True(expectedY.AsSpan().SequenceEqual(y)); + Assert.True(expectedU.AsSpan().SequenceEqual(u.Slice(0, expectedU.Length))); + Assert.True(expectedV.AsSpan().SequenceEqual(v.Slice(0, expectedV.Length))); } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 2925457475..5c86ffcd3b 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -526,6 +526,7 @@ namespace SixLabors.ImageSharp.Tests public static class Lossless { public const string Earth = "WebP/earth_lossless.webp"; + public const string Alpha = "WebP/lossless_alpha_small.webp"; public const string WithExif = "WebP/exif_lossless.webp"; public const string WithIccp = "WebP/lossless_with_iccp.webp"; public const string NoTransform1 = "WebP/lossless_vec_1_0.webp"; @@ -558,29 +559,29 @@ namespace SixLabors.ImageSharp.Tests public const string TwoTransforms12 = "WebP/lossless_vec_2_6.webp"; // substract_green, predictor public const string TwoTransforms13 = "WebP/lossless_vec_2_9.webp"; // color_indexing, predictor - public const string - ThreeTransforms1 = "WebP/color_cache_bits_11.webp"; // substract_green, predictor, cross_color + // substract_green, predictor, cross_color + public const string ThreeTransforms1 = "WebP/color_cache_bits_11.webp"; - public const string - ThreeTransforms2 = "WebP/lossless_vec_1_11.webp"; // color_indexing, predictor, cross_color + // color_indexing, predictor, cross_color + public const string ThreeTransforms2 = "WebP/lossless_vec_1_11.webp"; - public const string - ThreeTransforms3 = "WebP/lossless_vec_1_14.webp"; // substract_green, predictor, cross_color + // substract_green, predictor, cross_color + public const string ThreeTransforms3 = "WebP/lossless_vec_1_14.webp"; - public const string - ThreeTransforms4 = "WebP/lossless_vec_1_15.webp"; // color_indexing, predictor, cross_color + // color_indexing, predictor, cross_color + public const string ThreeTransforms4 = "WebP/lossless_vec_1_15.webp"; - public const string - ThreeTransforms5 = "WebP/lossless_vec_2_11.webp"; // color_indexing, predictor, cross_color + // color_indexing, predictor, cross_color + public const string ThreeTransforms5 = "WebP/lossless_vec_2_11.webp"; - public const string - ThreeTransforms6 = "WebP/lossless_vec_2_14.webp"; // substract_green, predictor, cross_color + // substract_green, predictor, cross_color + public const string ThreeTransforms6 = "WebP/lossless_vec_2_14.webp"; - public const string - ThreeTransforms7 = "WebP/lossless_vec_2_15.webp"; // color_indexing, predictor, cross_color + // color_indexing, predictor, cross_color + public const string ThreeTransforms7 = "WebP/lossless_vec_2_15.webp"; - public const string - BikeThreeTransforms = "WebP/bike_lossless.webp"; // substract_green, predictor, cross_color + // substract_green, predictor, cross_color + public const string BikeThreeTransforms = "WebP/bike_lossless.webp"; public const string BikeSmall = "WebP/bike_lossless_small.webp"; @@ -592,8 +593,7 @@ namespace SixLabors.ImageSharp.Tests public const string LossLessCorruptImage2 = "WebP/lossless_vec_2_7.webp"; // color_indexing, predictor. - public const string - LossLessCorruptImage3 = "WebP/lossless_color_transform.webp"; // cross_color, predictor + public const string LossLessCorruptImage3 = "WebP/lossless_color_transform.webp"; // cross_color, predictor public const string LossLessCorruptImage4 = "WebP/near_lossless_75.webp"; // predictor, cross_color. } @@ -666,7 +666,7 @@ namespace SixLabors.ImageSharp.Tests public const string Small03 = "WebP/small_1x13.webp"; public const string Small04 = "WebP/small_31x13.webp"; - // Lossy images with an alpha channel. + // Lossy images with a alpha channel. public const string Alpha1 = "WebP/lossy_alpha1.webp"; public const string Alpha2 = "WebP/lossy_alpha2.webp"; public const string Alpha3 = "WebP/alpha_color_cache.webp"; diff --git a/tests/Images/Input/WebP/lossless_alpha_small.webp b/tests/Images/Input/WebP/lossless_alpha_small.webp new file mode 100644 index 0000000000..304080f938 --- /dev/null +++ b/tests/Images/Input/WebP/lossless_alpha_small.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d078eb784835863f12ef25d9c1c135e79c2495532cec08da6f19c2e27c0cacee +size 1638