Browse Source

Write hasAlpha flag when encoding lossless webp

pull/1552/head
Brian Popow 5 years ago
parent
commit
b440d51331
  1. 24
      src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
  2. 311
      src/ImageSharp/Formats/WebP/Lossy/YuvConversion.cs
  3. 165
      src/ImageSharp/Formats/WebP/WebpCommonUtils.cs
  4. 214
      tests/ImageSharp.Tests/Formats/WebP/WebpCommonUtilsTests.cs
  5. 12
      tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs
  6. 480
      tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs
  7. 38
      tests/ImageSharp.Tests/TestImages.cs
  8. 3
      tests/Images/Input/WebP/lossless_alpha_small.webp

24
src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs

@ -194,14 +194,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
where TPixel : unmanaged, IPixel<TPixel>
{
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<uint> bgra = this.Bgra.GetSpan();
Span<uint> encodedData = this.EncodedData.GetSpan();
@ -345,17 +345,27 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <param name="image">The image to convert.</param>
/// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param>
private void ConvertPixelsToBgra<TPixel>(Image<TPixel> image, int width, int height)
/// <returns>true, if the image is non opaque.</returns>
private bool ConvertPixelsToBgra<TPixel>(Image<TPixel> image, int width, int height)
where TPixel : unmanaged, IPixel<TPixel>
{
bool nonOpaque = false;
Span<uint> bgra = this.Bgra.GetSpan();
Span<byte> bgraBytes = MemoryMarshal.Cast<uint, byte>(bgra);
int widthBytes = width * 4;
for (int y = 0; y < height; y++)
{
Span<TPixel> rowSpan = image.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(this.configuration, rowSpan, bgraBytes.Slice(y * widthBytes, widthBytes), width);
Span<byte> rowBytes = bgraBytes.Slice(y * widthBytes, widthBytes);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(this.configuration, rowSpan, rowBytes, width);
if (!nonOpaque)
{
Span<Bgra32> rowBgra = MemoryMarshal.Cast<byte, Bgra32>(rowBytes);
nonOpaque = WebpCommonUtils.CheckNonOpaque(rowBgra);
}
}
return nonOpaque;
}
/// <summary>

311
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<ushort> tmpRgb = memoryAllocator.Allocate<ushort>(4 * uvWidth);
using IMemoryOwner<Rgba32> rgbaRow0Buffer = memoryAllocator.Allocate<Rgba32>(width);
using IMemoryOwner<Rgba32> rgbaRow1Buffer = memoryAllocator.Allocate<Rgba32>(width);
using IMemoryOwner<Bgra32> bgraRow0Buffer = memoryAllocator.Allocate<Bgra32>(width);
using IMemoryOwner<Bgra32> bgraRow1Buffer = memoryAllocator.Allocate<Bgra32>(width);
Span<ushort> tmpRgbSpan = tmpRgb.GetSpan();
Span<Rgba32> rgbaRow0 = rgbaRow0Buffer.GetSpan();
Span<Rgba32> rgbaRow1 = rgbaRow1Buffer.GetSpan();
Span<Bgra32> bgraRow0 = bgraRow0Buffer.GetSpan();
Span<Bgra32> bgraRow1 = bgraRow1Buffer.GetSpan();
int uvRowIndex = 0;
int rowIndex;
for (rowIndex = 0; rowIndex < height - 1; rowIndex += 2)
{
Span<TPixel> rowSpan = image.GetPixelRowSpan(rowIndex);
Span<TPixel> nextRowSpan = image.GetPixelRowSpan(rowIndex + 1);
PixelOperations<TPixel>.Instance.ToRgba32(configuration, rowSpan, rgbaRow0);
PixelOperations<TPixel>.Instance.ToRgba32(configuration, nextRowSpan, rgbaRow1);
PixelOperations<TPixel>.Instance.ToBgra32(configuration, rowSpan, bgraRow0);
PixelOperations<TPixel>.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<TPixel> rowSpan = image.GetPixelRowSpan(rowIndex);
PixelOperations<TPixel>.Instance.ToRgba32(configuration, rowSpan, rgbaRow0);
ConvertRgbaToY(rgbaRow0, y.Slice(rowIndex * width), width);
PixelOperations<TPixel>.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);
}
}
/// <summary>
/// Checks if the pixel row is not opaque.
/// </summary>
/// <param name="row">The row to check.</param>
/// <returns>Returns true if alpha has non-0xff values.</returns>
public static unsafe bool CheckNonOpaque(Span<Rgba32> row)
{
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported)
{
ReadOnlySpan<byte> 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<byte> 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<byte> 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<byte> a0 = Avx.LoadVector256(src + i).AsByte();
Vector256<byte> a1 = Avx.LoadVector256(src + i + 32).AsByte();
Vector256<byte> a2 = Avx.LoadVector256(src + i + 64).AsByte();
Vector256<byte> a3 = Avx.LoadVector256(src + i + 96).AsByte();
Vector256<int> b0 = Avx2.And(a0, alphaMaskVector256).AsInt32();
Vector256<int> b1 = Avx2.And(a1, alphaMaskVector256).AsInt32();
Vector256<int> b2 = Avx2.And(a2, alphaMaskVector256).AsInt32();
Vector256<int> b3 = Avx2.And(a3, alphaMaskVector256).AsInt32();
Vector256<short> c0 = Avx2.PackSignedSaturate(b0, b1).AsInt16();
Vector256<short> c1 = Avx2.PackSignedSaturate(b2, b3).AsInt16();
Vector256<byte> d = Avx2.PackSignedSaturate(c0, c1).AsByte();
Vector256<byte> 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<byte> 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<byte> 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<byte> alphaMask, Vector128<byte> all0x80)
{
Vector128<byte> a0 = Sse2.LoadVector128(src + i).AsByte();
Vector128<byte> a1 = Sse2.LoadVector128(src + i + 16).AsByte();
Vector128<byte> a2 = Sse2.LoadVector128(src + i + 32).AsByte();
Vector128<byte> a3 = Sse2.LoadVector128(src + i + 48).AsByte();
Vector128<int> b0 = Sse2.And(a0, alphaMask).AsInt32();
Vector128<int> b1 = Sse2.And(a1, alphaMask).AsInt32();
Vector128<int> b2 = Sse2.And(a2, alphaMask).AsInt32();
Vector128<int> b3 = Sse2.And(a3, alphaMask).AsInt32();
Vector128<short> c0 = Sse2.PackSignedSaturate(b0, b1).AsInt16();
Vector128<short> c1 = Sse2.PackSignedSaturate(b2, b3).AsInt16();
Vector128<byte> d = Sse2.PackSignedSaturate(c0, c1).AsByte();
Vector128<byte> 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<byte> alphaMask, Vector128<byte> all0x80)
{
Vector128<byte> a0 = Sse2.LoadVector128(src + i).AsByte();
Vector128<byte> a1 = Sse2.LoadVector128(src + i + 16).AsByte();
Vector128<int> b0 = Sse2.And(a0, alphaMask).AsInt32();
Vector128<int> b1 = Sse2.And(a1, alphaMask).AsInt32();
Vector128<short> c = Sse2.PackSignedSaturate(b0, b1).AsInt16();
Vector128<byte> d = Sse2.PackSignedSaturate(c, c).AsByte();
Vector128<byte> bits = Sse2.CompareEqual(d, all0x80);
int mask = Sse2.MoveMask(bits);
if (mask != 0xFFFF)
{
return true;
}
return false;
}
#endif
/// <summary>
/// Converts a rgba pixel row to Y.
/// </summary>
@ -262,7 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
/// <param name="y">The destination span for y.</param>
/// <param name="width">The width.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ConvertRgbaToY(Span<Rgba32> rowSpan, Span<byte> y, int width)
public static void ConvertRgbaToY(Span<Bgra32> rowSpan, Span<byte> 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<Rgba32> rowSpan, Span<Rgba32> nextRowSpan, Span<ushort> dst, int width)
public static void AccumulateRgb(Span<Bgra32> rowSpan, Span<Bgra32> nextRowSpan, Span<ushort> 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<Rgba32> rowSpan, Span<Rgba32> nextRowSpan, Span<ushort> dst, int width)
public static void AccumulateRgba(Span<Bgra32> rowSpan, Span<Bgra32> nextRowSpan, Span<ushort> 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;

165
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);
}
/// <summary>
/// Checks if the pixel row is not opaque.
/// </summary>
/// <param name="row">The row to check.</param>
/// <returns>Returns true if alpha has non-0xff values.</returns>
public static unsafe bool CheckNonOpaque(Span<Bgra32> row)
{
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported)
{
ReadOnlySpan<byte> 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<byte> 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<byte> 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<byte> a0 = Avx.LoadVector256(src + i).AsByte();
Vector256<byte> a1 = Avx.LoadVector256(src + i + 32).AsByte();
Vector256<byte> a2 = Avx.LoadVector256(src + i + 64).AsByte();
Vector256<byte> a3 = Avx.LoadVector256(src + i + 96).AsByte();
Vector256<int> b0 = Avx2.And(a0, alphaMaskVector256).AsInt32();
Vector256<int> b1 = Avx2.And(a1, alphaMaskVector256).AsInt32();
Vector256<int> b2 = Avx2.And(a2, alphaMaskVector256).AsInt32();
Vector256<int> b3 = Avx2.And(a3, alphaMaskVector256).AsInt32();
Vector256<short> c0 = Avx2.PackSignedSaturate(b0, b1).AsInt16();
Vector256<short> c1 = Avx2.PackSignedSaturate(b2, b3).AsInt16();
Vector256<byte> d = Avx2.PackSignedSaturate(c0, c1).AsByte();
Vector256<byte> 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<byte> 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<byte> 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<byte> alphaMask, Vector128<byte> all0x80)
{
Vector128<byte> a0 = Sse2.LoadVector128(src + i).AsByte();
Vector128<byte> a1 = Sse2.LoadVector128(src + i + 16).AsByte();
Vector128<byte> a2 = Sse2.LoadVector128(src + i + 32).AsByte();
Vector128<byte> a3 = Sse2.LoadVector128(src + i + 48).AsByte();
Vector128<int> b0 = Sse2.And(a0, alphaMask).AsInt32();
Vector128<int> b1 = Sse2.And(a1, alphaMask).AsInt32();
Vector128<int> b2 = Sse2.And(a2, alphaMask).AsInt32();
Vector128<int> b3 = Sse2.And(a3, alphaMask).AsInt32();
Vector128<short> c0 = Sse2.PackSignedSaturate(b0, b1).AsInt16();
Vector128<short> c1 = Sse2.PackSignedSaturate(b2, b3).AsInt16();
Vector128<byte> d = Sse2.PackSignedSaturate(c0, c1).AsByte();
Vector128<byte> 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<byte> alphaMask, Vector128<byte> all0x80)
{
Vector128<byte> a0 = Sse2.LoadVector128(src + i).AsByte();
Vector128<byte> a1 = Sse2.LoadVector128(src + i + 16).AsByte();
Vector128<int> b0 = Sse2.And(a0, alphaMask).AsInt32();
Vector128<int> b1 = Sse2.And(a1, alphaMask).AsInt32();
Vector128<short> c = Sse2.PackSignedSaturate(b0, b1).AsInt16();
Vector128<byte> d = Sse2.PackSignedSaturate(c, c).AsByte();
Vector128<byte> bits = Sse2.CompareEqual(d, all0x80);
int mask = Sse2.MoveMask(bits);
if (mask != 0xFFFF)
{
return true;
}
return false;
}
#endif
}
}

214
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<Bgra32> row = MemoryMarshal.Cast<byte, Bgra32>(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<Bgra32> row = MemoryMarshal.Cast<byte, Bgra32>(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);
}
}
}

12
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<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(WebpDecoder))
{
image.DebugSave(provider);
image.CompareToOriginal(provider, ReferenceDecoder);
}
}
[Theory]
[WithFile(Lossless.NoTransform1, PixelTypes.Rgba32)]
[WithFile(Lossless.NoTransform2, PixelTypes.Rgba32)]

480
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<TPixel>(TestImageProvider<TPixel> provider)
@ -167,7 +131,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Webp
[Theory]
[WithTestPatternImages(31, 31, PixelTypes.Rgba32)]
public void ConvertRgbToYuv_WithAlpha_Works<TPixel>(TestImageProvider<TPixel> provider)
public void ConvertRgbToYuv_WithTestPattern_Works<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
// 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<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
// arrange
byte[] rowBytes =
using Image<TPixel> 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<byte> yBuffer = memoryAllocator.Allocate<byte>(pixels);
using System.Buffers.IMemoryOwner<byte> uBuffer = memoryAllocator.Allocate<byte>(uvWidth * image.Height);
using System.Buffers.IMemoryOwner<byte> vBuffer = memoryAllocator.Allocate<byte>(uvWidth * image.Height);
Span<byte> y = yBuffer.GetSpan();
Span<byte> u = uBuffer.GetSpan();
Span<byte> 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<Rgba32> row = MemoryMarshal.Cast<byte, Rgba32>(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<Rgba32> row = MemoryMarshal.Cast<byte, Rgba32>(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)));
}
}
}

38
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";

3
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
Loading…
Cancel
Save