Browse Source

A little cleanup and refactoring

pull/1552/head
Brian Popow 6 years ago
parent
commit
7396db5cfe
  1. 15
      src/ImageSharp/Formats/WebP/AlphaDecoder.cs
  2. 30
      src/ImageSharp/Formats/WebP/Filters/WebPFilterBase.cs
  3. 41
      src/ImageSharp/Formats/WebP/Filters/WebPFilterGradient.cs
  4. 71
      src/ImageSharp/Formats/WebP/Filters/WebPFilterHorizontal.cs
  5. 29
      src/ImageSharp/Formats/WebP/Filters/WebPFilterNone.cs
  6. 48
      src/ImageSharp/Formats/WebP/Filters/WebPFilterVertical.cs
  7. 332
      src/ImageSharp/Formats/WebP/LossyUtils.cs
  8. 2
      src/ImageSharp/Formats/WebP/Vp8BitReader.cs
  9. 43
      src/ImageSharp/Formats/WebP/Vp8Decoder.cs
  10. 22
      src/ImageSharp/Formats/WebP/Vp8Io.cs
  11. 4
      src/ImageSharp/Formats/WebP/Vp8LBitReader.cs
  12. 495
      src/ImageSharp/Formats/WebP/Vp8LookupTables.cs
  13. 7
      src/ImageSharp/Formats/WebP/Vp8MacroBlockData.cs
  14. 108
      src/ImageSharp/Formats/WebP/WebPDecoderBase.cs
  15. 580
      src/ImageSharp/Formats/WebP/WebPLookupTables.cs
  16. 108
      src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs
  17. 92
      src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs
  18. 4
      tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs
  19. 8
      tests/ImageSharp.Tests/Formats/WebP/WebPDecoderTests.cs
  20. 19
      tests/ImageSharp.Tests/Formats/WebP/WebPMetaDataTests.cs
  21. 7
      tests/ImageSharp.Tests/TestImages.cs

15
src/ImageSharp/Formats/WebP/AlphaDecoder.cs

@ -37,8 +37,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Taken from vp8l_dec.c AlphaApplyFilter
public void AlphaApplyFilter(
int firstRow, int lastRow,
Span<byte> output, int outputOffset,
int firstRow,
int lastRow,
Span<byte> output,
int outputOffset,
int stride)
{
if (!(this.Filter is WebPFilterNone))
@ -50,9 +52,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
this.Filter
.Unfilter(
prevLine, prevLineOffset,
output, outputOffset,
output, outputOffset,
prevLine,
prevLineOffset,
output,
outputOffset,
output,
outputOffset,
stride);
prevLineOffset = outputOffset;
outputOffset += stride;

30
src/ImageSharp/Formats/WebP/Filters/WebPFilterBase.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
@ -39,9 +39,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
int width);
public abstract void Filter(
Span<byte> input, int inputOffset,
int width, int height, int stride,
Span<byte> output, int outputOffset);
Span<byte> input,
int inputOffset,
int width,
int height,
int stride,
Span<byte> output,
int outputOffset);
protected static void SanityCheck(
Span<byte> input, Span<byte> output, int width, int numRows, int height, int stride, int row)
@ -57,10 +61,14 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
}
protected static void PredictLine(
Span<byte> src, int srcOffset,
Span<byte> pred, int predOffset,
Span<byte> dst, int dstOffset,
int length, bool inverse)
Span<byte> src,
int srcOffset,
Span<byte> pred,
int predOffset,
Span<byte> dst,
int dstOffset,
int length,
bool inverse)
{
if (inverse)
{
@ -80,8 +88,10 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
protected void UnfilterHorizontalOrVerticalCore(
byte pred,
Span<byte> input, int inputOffset,
Span<byte> output, int outputOffset,
Span<byte> input,
int inputOffset,
Span<byte> output,
int outputOffset,
int width)
{
for (int i = 0; i < width; i++)

41
src/ImageSharp/Formats/WebP/Filters/WebPFilterGradient.cs

@ -1,10 +1,12 @@
using System;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Formats.WebP.Filters
{
class WebPFilterGradient : WebPFilterBase
{
public override void Unfilter(
Span<byte> prevLine,
int? prevLineOffsetNullable,
@ -34,9 +36,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
}
public override void Filter(
Span<byte> input, int inputOffset,
int width, int height, int stride,
Span<byte> output, int outputOffset)
Span<byte> input,
int inputOffset,
int width,
int height,
int stride,
Span<byte> output,
int outputOffset)
{
// calling (input, width, height, stride, 0, height, 0, output
int row = 0;
@ -65,20 +71,27 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
{
output[outputOffset] = input[inputOffset];
PredictLine(
input, inputOffset+1,
preds, predsOffset,
output, outputOffset+1,
width-1,
input,
inputOffset + 1,
preds,
predsOffset,
output,
outputOffset + 1,
width - 1,
inverse);
}
while (row < lastRow)
{
PredictLine(
input, inputOffset,
preds, predsOffset-stride,
output, outputOffset,
1, inverse);
input,
inputOffset,
preds,
predsOffset - stride,
output,
outputOffset,
1,
inverse);
for (int w = 1; w < width; w++)
{
@ -100,4 +113,4 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
return (g & ~0xff) == 0 ? g : (g < 0) ? 0 : 255;
}
}
}
}

71
src/ImageSharp/Formats/WebP/Filters/WebPFilterHorizontal.cs

@ -1,13 +1,19 @@
using System;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Formats.WebP.Filters
{
class WebPFilterHorizontal : WebPFilterBase
{
public override void Unfilter(
Span<byte> prevLine, int? prevLineOffsetNullable,
Span<byte> input, int inputOffset,
Span<byte> output, int outputOffset,
Span<byte> prevLine,
int? prevLineOffsetNullable,
Span<byte> input,
int inputOffset,
Span<byte> output,
int outputOffset,
int width)
{
byte pred = prevLineOffsetNullable is int prevLineOffset
@ -16,15 +22,21 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
this.UnfilterHorizontalOrVerticalCore(
pred,
input, inputOffset,
output, outputOffset,
input,
inputOffset,
output,
outputOffset,
width);
}
public override void Filter(
Span<byte> input, int inputOffset,
int width, int height, int stride,
Span<byte> output, int outputOffset)
Span<byte> input,
int inputOffset,
int width,
int height,
int stride,
Span<byte> output,
int outputOffset)
{
int numRows = height;
int row = 0;
@ -51,16 +63,19 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
predsOffset = inputOffset;
}
if (row == 0)
{
// leftmost pixel is the same as Input for topmost scanline
output[0] = input[0];
PredictLine(
input, inputOffset + 1,
preds, predsOffset,
output, outputOffset + 1,
width - 1, inverse);
input,
inputOffset + 1,
preds,
predsOffset,
output,
outputOffset + 1,
width - 1,
inverse);
row = 1;
predsOffset += stride;
@ -68,19 +83,27 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
outputOffset += stride;
}
// filter line by line
// Filter line by line.
while (row < lastRow)
{
PredictLine(
input, inputOffset,
preds, predsOffset - stride,
output, 0,
1, inverse);
input,
inputOffset,
preds,
predsOffset - stride,
output,
0,
1,
inverse);
PredictLine(
input, inputOffset,
preds, predsOffset,
output,outputOffset + 1,
width - 1, inverse);
input,
inputOffset,
preds,
predsOffset,
output,
outputOffset + 1,
width - 1,
inverse);
row++;
predsOffset += stride;
@ -89,4 +112,4 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
}
}
}
}
}

29
src/ImageSharp/Formats/WebP/Filters/WebPFilterNone.cs

@ -1,14 +1,33 @@
using System;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Formats.WebP.Filters
{
// TODO: check if this is a filter or just a placeholder from the C implementation details
class WebPFilterNone : WebPFilterBase
{
public override void Unfilter(Span<byte> prevLine, int? prevLineOffset, Span<byte> input, int inputOffset, Span<byte> output, int outputOffset, int width)
{ }
public override void Unfilter(
Span<byte> prevLine,
int? prevLineOffset,
Span<byte> input,
int inputOffset,
Span<byte> output,
int outputOffset,
int width)
{
}
public override void Filter(Span<byte> input, int inputOffset, int width, int height, int stride, Span<byte> output, int outputOffset)
{ }
public override void Filter(
Span<byte> input,
int inputOffset,
int width,
int height,
int stride,
Span<byte> output,
int outputOffset)
{
}
}
}

48
src/ImageSharp/Formats/WebP/Filters/WebPFilterVertical.cs

@ -1,4 +1,7 @@
using System;
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Formats.WebP.Filters
{
@ -20,9 +23,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
}
public override void Filter(
Span<byte> input, int inputOffset,
int width, int height, int stride,
Span<byte> output, int outputOffset)
Span<byte> input,
int inputOffset,
int width,
int height,
int stride,
Span<byte> output,
int outputOffset)
{
int row = 0;
bool inverse = false;
@ -49,14 +56,19 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
if (row == 0)
{
// very first top-left pixel is copied.
// Very first top-left pixel is copied.
output[0] = input[0];
// rest of top scan-line is left-predicted:
// Rest of top scan-line is left-predicted:
PredictLine(
input, inputOffset + 1,
preds, predsOffset,
output, outputOffset + 1,
width - 1, inverse);
input,
inputOffset + 1,
preds,
predsOffset,
output,
outputOffset + 1,
width - 1,
inverse);
row = 1;
inputOffset += stride;
outputOffset += stride;
@ -66,14 +78,18 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
predsOffset -= stride;
}
// filter line-by-line
// Filter line-by-line.
while (row < lastRow)
{
PredictLine(
input, inputOffset,
preds, predsOffset,
output, outputOffset,
width, inverse);
input,
inputOffset,
preds,
predsOffset,
output,
outputOffset,
width,
inverse);
row++;
predsOffset += stride;
inputOffset += stride;
@ -81,4 +97,4 @@ namespace SixLabors.ImageSharp.Formats.WebP.Filters
}
}
}
}
}

332
src/ImageSharp/Formats/WebP/LossyUtils.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void DC16_C(Span<byte> dst, byte[] yuv, int offset)
public static void DC16(Span<byte> dst, byte[] yuv, int offset)
{
int dc = 16;
for (int j = 0; j < 16; ++j)
@ -28,12 +28,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put16(dc >> 5, dst);
}
public static void TM16_C(Span<byte> dst, byte[] yuv, int offset)
public static void TM16(Span<byte> dst, byte[] yuv, int offset)
{
TrueMotion(dst, yuv, offset, 16);
}
public static void VE16_C(Span<byte> dst, byte[] yuv, int offset)
public static void VE16(Span<byte> dst, byte[] yuv, int offset)
{
// vertical
Span<byte> src = yuv.AsSpan(offset - WebPConstants.Bps, 16);
@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void HE16_C(Span<byte> dst, byte[] yuv, int offset)
public static void HE16(Span<byte> dst, byte[] yuv, int offset)
{
// horizontal
for (int j = 16; j > 0; --j)
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void DC16NoTop_C(Span<byte> dst, byte[] yuv, int offset)
public static void DC16NoTop(Span<byte> dst, byte[] yuv, int offset)
{
// DC with top samples not available.
int dc = 8;
@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put16(dc >> 4, dst);
}
public static void DC16NoLeft_C(Span<byte> dst, byte[] yuv, int offset)
public static void DC16NoLeft(Span<byte> dst, byte[] yuv, int offset)
{
// DC with left samples not available.
int dc = 8;
@ -83,13 +83,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put16(dc >> 4, dst);
}
public static void DC16NoTopLeft_C(Span<byte> dst)
public static void DC16NoTopLeft(Span<byte> dst)
{
// DC with no top and left samples.
Put16(0x80, dst);
}
public static void DC8uv_C(Span<byte> dst, byte[] yuv, int offset)
public static void DC8uv(Span<byte> dst, byte[] yuv, int offset)
{
int dc0 = 8;
for (int i = 0; i < 8; ++i)
@ -101,13 +101,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put8x8uv((byte)(dc0 >> 4), dst);
}
public static void TM8uv_C(Span<byte> dst, byte[] yuv, int offset)
public static void TM8uv(Span<byte> dst, byte[] yuv, int offset)
{
// TrueMotion
TrueMotion(dst, yuv, offset, 8);
}
public static void VE8uv_C(Span<byte> dst, byte[] yuv, int offset)
public static void VE8uv(Span<byte> dst, byte[] yuv, int offset)
{
// vertical
Span<byte> src = yuv.AsSpan(offset - WebPConstants.Bps, 8);
@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void HE8uv_C(Span<byte> dst, byte[] yuv, int offset)
public static void HE8uv(Span<byte> dst, byte[] yuv, int offset)
{
// horizontal
for (int j = 0; j < 8; ++j)
@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void DC8uvNoTop_C(Span<byte> dst, byte[] yuv, int offset)
public static void DC8uvNoTop(Span<byte> dst, byte[] yuv, int offset)
{
// DC with no top samples.
int dc0 = 4;
@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put8x8uv((byte)(dc0 >> 3), dst);
}
public static void DC8uvNoLeft_C(Span<byte> dst, byte[] yuv, int offset)
public static void DC8uvNoLeft(Span<byte> dst, byte[] yuv, int offset)
{
// DC with no left samples.
int dc0 = 4;
@ -159,13 +159,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
Put8x8uv((byte)(dc0 >> 3), dst);
}
public static void DC8uvNoTopLeft_C(Span<byte> dst)
public static void DC8uvNoTopLeft(Span<byte> dst)
{
// DC with nothing.
Put8x8uv(0x80, dst);
}
public static void DC4_C(Span<byte> dst, byte[] yuv, int offset)
public static void DC4(Span<byte> dst, byte[] yuv, int offset)
{
int dc = 4;
for (int i = 0; i < 4; ++i)
@ -180,12 +180,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void TM4_C(Span<byte> dst, byte[] yuv, int offset)
public static void TM4(Span<byte> dst, byte[] yuv, int offset)
{
TrueMotion(dst, yuv, offset, 4);
}
public static void VE4_C(Span<byte> dst, byte[] yuv, int offset)
public static void VE4(Span<byte> dst, byte[] yuv, int offset)
{
// vertical
int topOffset = offset - WebPConstants.Bps;
@ -203,231 +203,231 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void HE4_C(Span<byte> dst, byte[] yuv, int offset)
public static void HE4(Span<byte> dst, byte[] yuv, int offset)
{
// horizontal
byte A = yuv[offset - 1 - WebPConstants.Bps];
byte B = yuv[offset - 1];
byte C = yuv[offset - 1 + WebPConstants.Bps];
byte D = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte E = yuv[offset - 1 + (3 * WebPConstants.Bps)];
uint val = 0x01010101U * Avg3(A, B, C);
byte a = yuv[offset - 1 - WebPConstants.Bps];
byte b = yuv[offset - 1];
byte c = yuv[offset - 1 + WebPConstants.Bps];
byte d = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte e = yuv[offset - 1 + (3 * WebPConstants.Bps)];
uint val = 0x01010101U * Avg3(a, b, c);
BinaryPrimitives.WriteUInt32BigEndian(dst, val);
val = 0x01010101U * Avg3(B, C, D);
val = 0x01010101U * Avg3(b, c, d);
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(WebPConstants.Bps), val);
val = 0x01010101U * Avg3(C, D, E);
val = 0x01010101U * Avg3(c, d, e);
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(2 * WebPConstants.Bps), val);
val = 0x01010101U * Avg3(D, E, E);
val = 0x01010101U * Avg3(d, e, e);
BinaryPrimitives.WriteUInt32BigEndian(dst.Slice(3 * WebPConstants.Bps), val);
}
public static void RD4_C(Span<byte> dst, byte[] yuv, int offset)
public static void RD4(Span<byte> dst, byte[] yuv, int offset)
{
// Down-right
byte I = yuv[offset - 1];
byte J = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte K = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte L = yuv[offset - 1 + (3 * WebPConstants.Bps)];
byte X = yuv[offset - 1 - WebPConstants.Bps];
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte D = yuv[offset + 3 - WebPConstants.Bps];
Dst(dst, 0, 3, Avg3(J, K, L));
byte ijk = Avg3(I, J, K);
byte i = yuv[offset - 1];
byte j = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte k = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte l = yuv[offset - 1 + (3 * WebPConstants.Bps)];
byte x = yuv[offset - 1 - WebPConstants.Bps];
byte a = yuv[offset - WebPConstants.Bps];
byte b = yuv[offset + 1 - WebPConstants.Bps];
byte c = yuv[offset + 2 - WebPConstants.Bps];
byte d = yuv[offset + 3 - WebPConstants.Bps];
Dst(dst, 0, 3, Avg3(j, k, l));
byte ijk = Avg3(i, j, k);
Dst(dst, 1, 3, ijk);
Dst(dst, 0, 2, ijk);
byte xij = Avg3(X, I, J);
byte xij = Avg3(x, i, j);
Dst(dst, 2, 3, xij);
Dst(dst, 1, 2, xij);
Dst(dst, 0, 1, xij);
byte axi = Avg3(A, X, I);
byte axi = Avg3(a, x, i);
Dst(dst, 3, 3, axi);
Dst(dst, 2, 2, axi);
Dst(dst, 1, 1, axi);
Dst(dst, 0, 0, axi);
byte bax = Avg3(B, A, X);
byte bax = Avg3(b, a, x);
Dst(dst, 3, 2, bax);
Dst(dst, 2, 1, bax);
Dst(dst, 1, 0, bax);
byte cba = Avg3(C, B, A);
byte cba = Avg3(c, b, a);
Dst(dst, 3, 1, cba);
Dst(dst, 2, 0, cba);
Dst(dst, 3, 0, Avg3(D, C, B));
Dst(dst, 3, 0, Avg3(d, c, b));
}
public static void VR4_C(Span<byte> dst, byte[] yuv, int offset)
public static void VR4(Span<byte> dst, byte[] yuv, int offset)
{
// Vertical-Right
byte I = yuv[offset - 1];
byte J = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte K = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte X = yuv[offset - 1 - WebPConstants.Bps];
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte D = yuv[offset + 3 - WebPConstants.Bps];
byte xa = Avg2(X, A);
byte i = yuv[offset - 1];
byte j = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte k = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte x = yuv[offset - 1 - WebPConstants.Bps];
byte a = yuv[offset - WebPConstants.Bps];
byte b = yuv[offset + 1 - WebPConstants.Bps];
byte c = yuv[offset + 2 - WebPConstants.Bps];
byte d = yuv[offset + 3 - WebPConstants.Bps];
byte xa = Avg2(x, a);
Dst(dst, 0, 0, xa);
Dst(dst, 1, 2, xa);
byte ab = Avg2(A, B);
byte ab = Avg2(a, b);
Dst(dst, 1, 0, ab);
Dst(dst, 2, 2, ab);
byte bc = Avg2(B, C);
byte bc = Avg2(b, c);
Dst(dst, 2, 0, bc);
Dst(dst, 3, 2, bc);
Dst(dst, 3, 0, Avg2(C, D));
Dst(dst, 0, 3, Avg3(K, J, I));
Dst(dst, 0, 2, Avg3(J, I, X));
byte ixa = Avg3(I, X, A);
Dst(dst, 3, 0, Avg2(c, d));
Dst(dst, 0, 3, Avg3(k, j, i));
Dst(dst, 0, 2, Avg3(j, i, x));
byte ixa = Avg3(i, x, a);
Dst(dst, 0, 1, ixa);
Dst(dst, 1, 3, ixa);
byte xab = Avg3(X, A, B);
byte xab = Avg3(x, a, b);
Dst(dst, 1, 1, xab);
Dst(dst, 2, 3, xab);
byte abc = Avg3(A, B, C);
byte abc = Avg3(a, b, c);
Dst(dst, 2, 1, abc);
Dst(dst, 3, 3, abc);
Dst(dst, 3, 1, Avg3(B, C, D));
Dst(dst, 3, 1, Avg3(b, c, d));
}
public static void LD4_C(Span<byte> dst, byte[] yuv, int offset)
public static void LD4(Span<byte> dst, byte[] yuv, int offset)
{
// Down-Left
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte D = yuv[offset + 3 - WebPConstants.Bps];
byte E = yuv[offset + 4 - WebPConstants.Bps];
byte F = yuv[offset + 5 - WebPConstants.Bps];
byte G = yuv[offset + 6 - WebPConstants.Bps];
byte H = yuv[offset + 7 - WebPConstants.Bps];
Dst(dst, 0, 0, Avg3(A, B, C));
byte bcd = Avg3(B, C, D);
byte a = yuv[offset - WebPConstants.Bps];
byte b = yuv[offset + 1 - WebPConstants.Bps];
byte c = yuv[offset + 2 - WebPConstants.Bps];
byte d = yuv[offset + 3 - WebPConstants.Bps];
byte e = yuv[offset + 4 - WebPConstants.Bps];
byte f = yuv[offset + 5 - WebPConstants.Bps];
byte g = yuv[offset + 6 - WebPConstants.Bps];
byte h = yuv[offset + 7 - WebPConstants.Bps];
Dst(dst, 0, 0, Avg3(a, b, c));
byte bcd = Avg3(b, c, d);
Dst(dst, 1, 0, bcd);
Dst(dst, 0, 1, bcd);
byte cde = Avg3(C, D, E);
byte cde = Avg3(c, d, e);
Dst(dst, 2, 0, cde);
Dst(dst, 1, 1, cde);
Dst(dst, 0, 2, cde);
byte def = Avg3(D, E, F);
byte def = Avg3(d, e, f);
Dst(dst, 3, 0, def);
Dst(dst, 2, 1, def);
Dst(dst, 1, 2, def);
Dst(dst, 0, 3, def);
byte efg = Avg3(E, F, G);
byte efg = Avg3(e, f, g);
Dst(dst, 3, 1, efg);
Dst(dst, 2, 2, efg);
Dst(dst, 1, 3, efg);
byte fgh = Avg3(F, G, H);
byte fgh = Avg3(f, g, h);
Dst(dst, 3, 2, fgh);
Dst(dst, 2, 3, fgh);
Dst(dst, 3, 3, Avg3(G, H, H));
Dst(dst, 3, 3, Avg3(g, h, h));
}
public static void VL4_C(Span<byte> dst, byte[] yuv, int offset)
public static void VL4(Span<byte> dst, byte[] yuv, int offset)
{
// Vertical-Left
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte D = yuv[offset + 3 - WebPConstants.Bps];
byte E = yuv[offset + 4 - WebPConstants.Bps];
byte F = yuv[offset + 5 - WebPConstants.Bps];
byte G = yuv[offset + 6 - WebPConstants.Bps];
byte H = yuv[offset + 7 - WebPConstants.Bps];
Dst(dst, 0, 0, Avg2(A, B));
byte bc = Avg2(B, C);
byte a = yuv[offset - WebPConstants.Bps];
byte b = yuv[offset + 1 - WebPConstants.Bps];
byte c = yuv[offset + 2 - WebPConstants.Bps];
byte d = yuv[offset + 3 - WebPConstants.Bps];
byte e = yuv[offset + 4 - WebPConstants.Bps];
byte f = yuv[offset + 5 - WebPConstants.Bps];
byte g = yuv[offset + 6 - WebPConstants.Bps];
byte h = yuv[offset + 7 - WebPConstants.Bps];
Dst(dst, 0, 0, Avg2(a, b));
byte bc = Avg2(b, c);
Dst(dst, 1, 0, bc);
Dst(dst, 0, 2, bc);
byte cd = Avg2(C, D);
byte cd = Avg2(c, d);
Dst(dst, 2, 0, cd);
Dst(dst, 1, 2, cd);
byte de = Avg2(D, E);
byte de = Avg2(d, e);
Dst(dst, 3, 0, de);
Dst(dst, 2, 2, de);
Dst(dst, 0, 1, Avg3(A, B, C));
byte bcd = Avg3(B, C, D);
Dst(dst, 0, 1, Avg3(a, b, c));
byte bcd = Avg3(b, c, d);
Dst(dst, 1, 1, bcd);
Dst(dst, 0, 3, bcd);
byte cde = Avg3(C, D, E);
byte cde = Avg3(c, d, e);
Dst(dst, 2, 1, cde);
Dst(dst, 1, 3, cde);
byte def = Avg3(D, E, F);
byte def = Avg3(d, e, f);
Dst(dst, 3, 1, def);
Dst(dst, 2, 3, def);
Dst(dst, 3, 2, Avg3(E, F, G));
Dst(dst, 3, 3, Avg3(F, G, H));
Dst(dst, 3, 2, Avg3(e, f, g));
Dst(dst, 3, 3, Avg3(f, g, h));
}
public static void HD4_C(Span<byte> dst, byte[] yuv, int offset)
public static void HD4(Span<byte> dst, byte[] yuv, int offset)
{
// Horizontal-Down
byte I = yuv[offset - 1];
byte J = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte K = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte L = yuv[offset - 1 + (3 * WebPConstants.Bps)];
byte X = yuv[offset - 1 - WebPConstants.Bps];
byte A = yuv[offset - WebPConstants.Bps];
byte B = yuv[offset + 1 - WebPConstants.Bps];
byte C = yuv[offset + 2 - WebPConstants.Bps];
byte ix = Avg2(I, X);
byte i = yuv[offset - 1];
byte j = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte k = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte l = yuv[offset - 1 + (3 * WebPConstants.Bps)];
byte x = yuv[offset - 1 - WebPConstants.Bps];
byte a = yuv[offset - WebPConstants.Bps];
byte b = yuv[offset + 1 - WebPConstants.Bps];
byte c = yuv[offset + 2 - WebPConstants.Bps];
byte ix = Avg2(i, x);
Dst(dst, 0, 0, ix);
Dst(dst, 2, 1, ix);
byte ji = Avg2(J, I);
byte ji = Avg2(j, i);
Dst(dst, 0, 1, ji);
Dst(dst, 2, 2, ji);
byte kj = Avg2(K, J);
byte kj = Avg2(k, j);
Dst(dst, 0, 2, kj);
Dst(dst, 2, 3, kj);
Dst(dst, 0, 3, Avg2(L, K));
Dst(dst, 3, 0, Avg3(A, B, C));
Dst(dst, 2, 0, Avg3(X, A, B));
byte ixa = Avg3(I, X, A);
Dst(dst, 0, 3, Avg2(l, k));
Dst(dst, 3, 0, Avg3(a, b, c));
Dst(dst, 2, 0, Avg3(x, a, b));
byte ixa = Avg3(i, x, a);
Dst(dst, 1, 0, ixa);
Dst(dst, 3, 1, ixa);
byte jix = Avg3(J, I, X);
byte jix = Avg3(j, i, x);
Dst(dst, 1, 1, jix);
Dst(dst, 3, 2, jix);
byte kji = Avg3(K, J, I);
byte kji = Avg3(k, j, i);
Dst(dst, 1, 2, kji);
Dst(dst, 3, 3, kji);
Dst(dst, 1, 3, Avg3(L, K, J));
Dst(dst, 1, 3, Avg3(l, k, j));
}
public static void HU4_C(Span<byte> dst, byte[] yuv, int offset)
public static void HU4(Span<byte> dst, byte[] yuv, int offset)
{
// Horizontal-Up
byte I = yuv[offset - 1];
byte J = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte K = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte L = yuv[offset - 1 + (3 * WebPConstants.Bps)];
byte i = yuv[offset - 1];
byte j = yuv[offset - 1 + (1 * WebPConstants.Bps)];
byte k = yuv[offset - 1 + (2 * WebPConstants.Bps)];
byte l = yuv[offset - 1 + (3 * WebPConstants.Bps)];
Dst(dst, 0, 0, Avg2(I, J));
byte jk = Avg2(J, K);
Dst(dst, 0, 0, Avg2(i, j));
byte jk = Avg2(j, k);
Dst(dst, 2, 0, jk);
Dst(dst, 0, 1, jk);
byte kl = Avg2(K, L);
byte kl = Avg2(k, l);
Dst(dst, 2, 1, kl);
Dst(dst, 0, 2, kl);
Dst(dst, 1, 0, Avg3(I, J, K));
byte jkl = Avg3(J, K, L);
Dst(dst, 1, 0, Avg3(i, j, k));
byte jkl = Avg3(j, k, l);
Dst(dst, 3, 0, jkl);
Dst(dst, 1, 1, jkl);
byte kll = Avg3(K, L, L);
byte kll = Avg3(k, l, l);
Dst(dst, 3, 1, kll);
Dst(dst, 1, 2, kll);
Dst(dst, 3, 2, L);
Dst(dst, 2, 2, L);
Dst(dst, 0, 3, L);
Dst(dst, 1, 3, L);
Dst(dst, 2, 3, L);
Dst(dst, 3, 3, L);
Dst(dst, 3, 2, l);
Dst(dst, 2, 2, l);
Dst(dst, 0, 3, l);
Dst(dst, 1, 3, l);
Dst(dst, 2, 3, l);
Dst(dst, 3, 3, l);
}
public static void Transform(Span<short> src, Span<byte> dst, bool doTwo)
@ -743,56 +743,56 @@ namespace SixLabors.ImageSharp.Formats.WebP
private static void DoFilter2(byte[] p, int offset, int step)
{
// 4 pixels in, 2 pixels out
// 4 pixels in, 2 pixels out.
int p1 = p[offset - (2 * step)];
int p0 = p[offset - step];
int q0 = p[offset];
int q1 = p[offset + step];
int a = (3 * (q0 - p0)) + Vp8LookupTables.Sclip1[p1 - q1];
int a1 = Vp8LookupTables.Sclip2[(a + 4) >> 3];
int a2 = Vp8LookupTables.Sclip2[(a + 3) >> 3];
p[offset - step] = Vp8LookupTables.Clip1[p0 + a2];
p[offset] = Vp8LookupTables.Clip1[q0 - a1];
int a = (3 * (q0 - p0)) + WebPLookupTables.Sclip1[p1 - q1];
int a1 = WebPLookupTables.Sclip2[(a + 4) >> 3];
int a2 = WebPLookupTables.Sclip2[(a + 3) >> 3];
p[offset - step] = WebPLookupTables.Clip1[p0 + a2];
p[offset] = WebPLookupTables.Clip1[q0 - a1];
}
private static void DoFilter4(byte[] p, int offset, int step)
{
// 4 pixels in, 4 pixels out
// 4 pixels in, 4 pixels out.
int p1 = p[offset - (2 * step)];
int p0 = p[offset - step];
int q0 = p[offset];
int q1 = p[offset + step];
int a = 3 * (q0 - p0);
int a1 = Vp8LookupTables.Sclip2[(a + 4) >> 3];
int a2 = Vp8LookupTables.Sclip2[(a + 3) >> 3];
int a1 = WebPLookupTables.Sclip2[(a + 4) >> 3];
int a2 = WebPLookupTables.Sclip2[(a + 3) >> 3];
int a3 = (a1 + 1) >> 1;
p[offset - (2 * step)] = Vp8LookupTables.Clip1[p1 + a3];
p[offset - step] = Vp8LookupTables.Clip1[p0 + a2];
p[offset] = Vp8LookupTables.Clip1[q0 - a1];
p[offset + step] = Vp8LookupTables.Clip1[q1 - a3];
p[offset - (2 * step)] = WebPLookupTables.Clip1[p1 + a3];
p[offset - step] = WebPLookupTables.Clip1[p0 + a2];
p[offset] = WebPLookupTables.Clip1[q0 - a1];
p[offset + step] = WebPLookupTables.Clip1[q1 - a3];
}
private static void DoFilter6(byte[] p, int offset, int step)
{
// 6 pixels in, 6 pixels out
// 6 pixels in, 6 pixels out.
int p2 = p[offset - (3 * step)];
int p1 = p[offset - (2 * step)];
int p0 = p[offset - step];
int q0 = p[offset];
int q1 = p[offset + step];
int q2 = p[offset + (2 * step)];
int a = Vp8LookupTables.Sclip1[(3 * (q0 - p0)) + Vp8LookupTables.Sclip1[p1 - q1]];
int a = WebPLookupTables.Sclip1[(3 * (q0 - p0)) + WebPLookupTables.Sclip1[p1 - q1]];
// a is in [-128,127], a1 in [-27,27], a2 in [-18,18] and a3 in [-9,9]
int a1 = ((27 * a) + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7
int a2 = ((18 * a) + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7
int a3 = ((9 * a) + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7
p[offset - (3 * step)] = Vp8LookupTables.Clip1[p2 + a3];
p[offset - (2 * step)] = Vp8LookupTables.Clip1[p1 + a2];
p[offset - step] = Vp8LookupTables.Clip1[p0 + a1];
p[offset] = Vp8LookupTables.Clip1[q0 - a1];
p[offset + step] = Vp8LookupTables.Clip1[q1 - a2];
p[offset + (2 * step)] = Vp8LookupTables.Clip1[q2 - a3];
p[offset - (3 * step)] = WebPLookupTables.Clip1[p2 + a3];
p[offset - (2 * step)] = WebPLookupTables.Clip1[p1 + a2];
p[offset - step] = WebPLookupTables.Clip1[p0 + a1];
p[offset] = WebPLookupTables.Clip1[q0 - a1];
p[offset + step] = WebPLookupTables.Clip1[q1 - a2];
p[offset + (2 * step)] = WebPLookupTables.Clip1[q2 - a3];
}
private static bool NeedsFilter(byte[] p, int offset, int step, int t)
@ -801,7 +801,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
int p0 = p[offset - step];
int q0 = p[offset];
int q1 = p[offset + step];
return ((4 * Vp8LookupTables.Abs0[p0 - q0]) + Vp8LookupTables.Abs0[p1 - q1]) <= t;
return ((4 * WebPLookupTables.Abs0[p0 - q0]) + WebPLookupTables.Abs0[p1 - q1]) <= t;
}
private static bool NeedsFilter2(byte[] p, int offset, int step, int t, int it)
@ -814,14 +814,14 @@ namespace SixLabors.ImageSharp.Formats.WebP
int q1 = p[offset + step];
int q2 = p[offset + (2 * step)];
int q3 = p[offset + (3 * step)];
if (((4 * Vp8LookupTables.Abs0[p0 - q0]) + Vp8LookupTables.Abs0[p1 - q1]) > t)
if (((4 * WebPLookupTables.Abs0[p0 - q0]) + WebPLookupTables.Abs0[p1 - q1]) > t)
{
return false;
}
return Vp8LookupTables.Abs0[p3 - p2] <= it && Vp8LookupTables.Abs0[p2 - p1] <= it &&
Vp8LookupTables.Abs0[p1 - p0] <= it && Vp8LookupTables.Abs0[q3 - q2] <= it &&
Vp8LookupTables.Abs0[q2 - q1] <= it && Vp8LookupTables.Abs0[q1 - q0] <= it;
return WebPLookupTables.Abs0[p3 - p2] <= it && WebPLookupTables.Abs0[p2 - p1] <= it &&
WebPLookupTables.Abs0[p1 - p0] <= it && WebPLookupTables.Abs0[q3 - q2] <= it &&
WebPLookupTables.Abs0[q2 - q1] <= it && WebPLookupTables.Abs0[q1 - q0] <= it;
}
private static bool Hev(byte[] p, int offset, int step, int thresh)
@ -830,7 +830,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
int p0 = p[offset - step];
int q0 = p[offset];
int q1 = p[offset + step];
return (Vp8LookupTables.Abs0[p1 - p0] > thresh) || (Vp8LookupTables.Abs0[q1 - q0] > thresh);
return (WebPLookupTables.Abs0[p1 - p0] > thresh) || (WebPLookupTables.Abs0[q1 - q0] > thresh);
}
private static int MultHi(int v, int coeff)

2
src/ImageSharp/Formats/WebP/Vp8BitReader.cs

@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
n >>= 8;
}
return logValue + Vp8LookupTables.LogTable8bit[n];
return logValue + WebPLookupTables.LogTable8bit[n];
}
}
}

43
src/ImageSharp/Formats/WebP/Vp8Decoder.cs

@ -8,6 +8,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
internal class Vp8Decoder
{
private Vp8MacroBlock leftMacroBlock;
public Vp8Decoder(Vp8FrameHeader frameHeader, Vp8PictureHeader pictureHeader, Vp8SegmentHeader segmentHeader, Vp8Proba probabilities)
{
this.FilterHeader = new Vp8FilterHeader();
@ -53,12 +55,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
int extraRows = WebPConstants.FilterExtraRows[2]; // TODO: assuming worst case: complex filter
int extraY = extraRows * this.CacheYStride;
int extraUv = (extraRows / 2) * this.CacheUvStride;
this.CacheY = new byte[width * height + extraY + 256]; // TODO: this is way too much mem, figure out what the min req is.
this.CacheU = new byte[width * height + extraUv + 256];
this.CacheV = new byte[width * height + extraUv + 256];
this.TmpYBuffer = new byte[width * height + extraY]; // TODO: figure out min buffer length
this.TmpUBuffer = new byte[width * height + extraUv]; // TODO: figure out min buffer length
this.TmpVBuffer = new byte[width * height + extraUv]; // TODO: figure out min buffer length
this.CacheY = new byte[(width * height) + extraY + 256]; // TODO: this is way too much mem, figure out what the min req is.
this.CacheU = new byte[(width * height) + extraUv + 256];
this.CacheV = new byte[(width * height) + extraUv + 256];
this.TmpYBuffer = new byte[(width * height) + extraY]; // TODO: figure out min buffer length
this.TmpUBuffer = new byte[(width * height) + extraUv]; // TODO: figure out min buffer length
this.TmpVBuffer = new byte[(width * height) + extraUv]; // TODO: figure out min buffer length
this.Bgr = new byte[width * height * 4];
for (int i = 0; i < this.YuvBuffer.Length; i++)
@ -88,38 +90,47 @@ namespace SixLabors.ImageSharp.Formats.WebP
public Vp8SegmentHeader SegmentHeader { get; }
// number of partitions minus one.
/// <summary>
/// Gets or sets the number of partitions minus one.
/// </summary>
public int NumPartsMinusOne { get; set; }
// per-partition boolean decoders.
/// <summary>
/// Gets the per-partition boolean decoders.
/// </summary>
public Vp8BitReader[] Vp8BitReaders { get; }
public bool Dither { get; set; }
/// <summary>
/// Gets or sets dequantization matrices (one set of DC/AC dequant factor per segment).
/// Gets the dequantization matrices (one set of DC/AC dequant factor per segment).
/// </summary>
public Vp8QuantMatrix[] DeQuantMatrices { get; }
/// <summary>
/// Gets or sets a value indicating whether to use the skip probabilities.
/// </summary>
public bool UseSkipProbability { get; set; }
public byte SkipProbability { get; set; }
public Vp8Proba Probabilities { get; set; }
// top intra modes values: 4 * MbWidth
/// <summary>
/// Gets or sets the top intra modes values: 4 * MbWidth.
/// </summary>
public byte[] IntraT { get; set; }
// left intra modes values
/// <summary>
/// Gets the left intra modes values.
/// </summary>
public byte[] IntraL { get; }
/// <summary>
/// Gets or sets the width in macroblock units.
/// Gets the width in macroblock units.
/// </summary>
public int MbWidth { get; }
/// <summary>
/// Gets or sets the height in macroblock units.
/// Gets the height in macroblock units.
/// </summary>
public int MbHeight { get; }
@ -198,8 +209,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public Vp8FilterInfo[] FilterInfo { get; set; }
private Vp8MacroBlock leftMacroBlock;
public Vp8MacroBlock CurrentMacroBlock
{
get

22
src/ImageSharp/Formats/WebP/Vp8Io.cs

@ -5,59 +5,59 @@ using System;
namespace SixLabors.ImageSharp.Formats.WebP
{
public ref struct Vp8Io
internal ref struct Vp8Io
{
/// <summary>
/// Picture Width in pixels (invariable).
/// Gets or sets the picture width in pixels (invariable).
/// Original, uncropped dimensions.
/// The actual area passed to put() is stored in <see cref="MbW"/> /> field.
/// </summary>
public int Width { get; set; }
/// <summary>
/// Picture Width in pixels (invariable).
/// Gets or sets the picture height in pixels (invariable).
/// Original, uncropped dimensions.
/// The actual area passed to put() is stored in <see cref="MbH"/> /> field.
/// </summary>
public int Height { get; set; }
/// <summary>
/// Position of the current Rows (in pixels)
/// Gets or sets the y-position of the current macroblock.
/// </summary>
public int MbY { get; set; }
/// <summary>
/// number of columns in the sample
/// Gets or sets the macroblock width.
/// </summary>
public int MbW { get; set; }
/// <summary>
/// Number of Rows in the sample
/// Gets or sets the macroblock height.
/// </summary>
public int MbH { get; set; }
/// <summary>
/// Rows to copy (in YUV format)
/// Rows to copy (in YUV format).
/// </summary>
public Span<byte> Y { get; set; }
/// <summary>
/// Rows to copy (in YUV format)
/// Rows to copy (in YUV format).
/// </summary>
public Span<byte> U { get; set; }
/// <summary>
/// Rows to copy (in YUV format)
/// Rows to copy (in YUV format).
/// </summary>
public Span<byte> V { get; set; }
/// <summary>
/// Row stride for luma
/// Gets or sets the row stride for luma.
/// </summary>
public int YStride { get; set; }
/// <summary>
/// Row stride for chroma
/// Gets or sets the row stride for chroma.
/// </summary>
public int UvStride { get; set; }

4
src/ImageSharp/Formats/WebP/Vp8LBitReader.cs

@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
private const int Vp8LWbits = 32;
private readonly uint[] BitMask =
private readonly uint[] bitMask =
{
0,
0x000001, 0x000003, 0x000007, 0x00000f,
@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
if (!this.eos && nBits <= Vp8LMaxNumBitRead)
{
ulong val = this.PrefetchBits() & this.BitMask[nBits];
ulong val = this.PrefetchBits() & this.bitMask[nBits];
int newBits = this.bitPos + nBits;
this.bitPos = newBits;
this.ShiftBytes();

495
src/ImageSharp/Formats/WebP/Vp8LookupTables.cs

@ -1,495 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
namespace SixLabors.ImageSharp.Formats.WebP
{
internal static class Vp8LookupTables
{
public static readonly Dictionary<int, byte> Abs0;
public static readonly Dictionary<int, byte> Clip1;
public static readonly Dictionary<int, sbyte> Sclip1;
public static readonly Dictionary<int, sbyte> Sclip2;
public static readonly byte[,][] ModesProba = new byte[10, 10][];
// 31 ^ clz(i)
public static readonly byte[] LogTable8bit =
{
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
// Paragraph 14.1
public static readonly int[] DcTable =
{
4, 5, 6, 7, 8, 9, 10, 10,
11, 12, 13, 14, 15, 16, 17, 17,
18, 19, 20, 20, 21, 21, 22, 22,
23, 23, 24, 25, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36,
37, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89,
91, 93, 95, 96, 98, 100, 101, 102,
104, 106, 108, 110, 112, 114, 116, 118,
122, 124, 126, 128, 130, 132, 134, 136,
138, 140, 143, 145, 148, 151, 154, 157
};
// Paragraph 14.1
public static readonly int[] AcTable =
{
4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 60,
62, 64, 66, 68, 70, 72, 74, 76,
78, 80, 82, 84, 86, 88, 90, 92,
94, 96, 98, 100, 102, 104, 106, 108,
110, 112, 114, 116, 119, 122, 125, 128,
131, 134, 137, 140, 143, 146, 149, 152,
155, 158, 161, 164, 167, 170, 173, 177,
181, 185, 189, 193, 197, 201, 205, 209,
213, 217, 221, 225, 229, 234, 239, 245,
249, 254, 259, 264, 269, 274, 279, 284
};
// Paragraph 13
public static readonly byte[,,,] CoeffsUpdateProba =
{
{ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 },
{ 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
}
},
{ { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 },
{ 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 }
},
{ { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
}
},
{ { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 },
{ 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 }
},
{ { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
}
},
{ { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 },
{ 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
}
}
};
// Paragraph 13.5: Default Token Probability Table.
public static readonly byte[,,,] DefaultCoeffsProba =
{
{
{ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
},
{ { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 },
{ 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 },
{ 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 }
},
{ { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 },
{ 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 },
{ 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 },
},
{ { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 },
{ 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 },
{ 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 },
},
{ { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 },
{ 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 },
{ 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 }
},
{ { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 },
{ 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 },
{ 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 }
},
{ { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 },
{ 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 },
{ 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 }
},
{ { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
}
},
{
{ { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 },
{ 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 },
{ 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 }
},
{ { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 },
{ 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 },
{ 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 }
},
{ { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 },
{ 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 },
{ 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 }
},
{ { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 },
{ 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 },
{ 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 }
},
{ { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 },
{ 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 },
{ 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 }
},
{ { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 },
{ 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 },
{ 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 }
},
{ { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 },
{ 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 },
{ 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 }
},
{ { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 },
{ 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 }
}
},
{ { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 },
{ 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 },
{ 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 }
},
{ { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 },
{ 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 },
{ 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 }
},
{ { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 },
{ 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 },
{ 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 }
},
{ { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 },
{ 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 }
},
{ { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 },
{ 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
},
{ { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
},
{ { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 55, 93, 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 }
}
},
{
{ { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 },
{ 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 },
{ 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 }
},
{ { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 },
{ 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 },
{ 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 }
},
{ { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 },
{ 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 },
{ 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 }
},
{ { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 },
{ 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 },
{ 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 }
},
{ { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 },
{ 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 },
{ 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 }
},
{ { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 },
{ 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 },
{ 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 }
},
{ { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 },
{ 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 },
{ 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 }
},
{ { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
}
}
};
static Vp8LookupTables()
{
// TODO: maybe use hashset here
Abs0 = new Dictionary<int, byte>();
for (int i = -255; i <= 255; ++i)
{
Abs0[i] = (byte)((i < 0) ? -i : i);
}
Clip1 = new Dictionary<int, byte>();
for (int i = -255; i <= 255 + 255; ++i)
{
Clip1[i] = (byte)((i < 0) ? 0 : (i > 255) ? 255 : i);
}
Sclip1 = new Dictionary<int, sbyte>();
for (int i = -1020; i <= 1020; ++i)
{
Sclip1[i] = (sbyte)((i < -128) ? -128 : (i > 127) ? 127 : i);
}
Sclip2 = new Dictionary<int, sbyte>();
for (int i = -112; i <= 112; ++i)
{
Sclip2[i] = (sbyte)((i < -16) ? -16 : (i > 15) ? 15 : i);
}
InitializeModesProbabilities();
}
private static void InitializeModesProbabilities()
{
// Paragraph 11.5
ModesProba[0, 0] = new byte[] { 231, 120, 48, 89, 115, 113, 120, 152, 112 };
ModesProba[0, 1] = new byte[] { 152, 179, 64, 126, 170, 118, 46, 70, 95 };
ModesProba[0, 2] = new byte[] { 175, 69, 143, 80, 85, 82, 72, 155, 103 };
ModesProba[0, 3] = new byte[] { 56, 58, 10, 171, 218, 189, 17, 13, 152 };
ModesProba[0, 4] = new byte[] { 114, 26, 17, 163, 44, 195, 21, 10, 173 };
ModesProba[0, 5] = new byte[] { 121, 24, 80, 195, 26, 62, 44, 64, 85 };
ModesProba[0, 6] = new byte[] { 144, 71, 10, 38, 171, 213, 144, 34, 26 };
ModesProba[0, 7] = new byte[] { 170, 46, 55, 19, 136, 160, 33, 206, 71 };
ModesProba[0, 8] = new byte[] { 63, 20, 8, 114, 114, 208, 12, 9, 226 };
ModesProba[0, 9] = new byte[] { 81, 40, 11, 96, 182, 84, 29, 16, 36 };
ModesProba[1, 0] = new byte[] { 134, 183, 89, 137, 98, 101, 106, 165, 148 };
ModesProba[1, 1] = new byte[] { 72, 187, 100, 130, 157, 111, 32, 75, 80 };
ModesProba[1, 2] = new byte[] { 66, 102, 167, 99, 74, 62, 40, 234, 128 };
ModesProba[1, 3] = new byte[] { 41, 53, 9, 178, 241, 141, 26, 8, 107 };
ModesProba[1, 4] = new byte[] { 74, 43, 26, 146, 73, 166, 49, 23, 157 };
ModesProba[1, 5] = new byte[] { 65, 38, 105, 160, 51, 52, 31, 115, 128 };
ModesProba[1, 6] = new byte[] { 104, 79, 12, 27, 217, 255, 87, 17, 7 };
ModesProba[1, 7] = new byte[] { 87, 68, 71, 44, 114, 51, 15, 186, 23 };
ModesProba[1, 8] = new byte[] { 47, 41, 14, 110, 182, 183, 21, 17, 194 };
ModesProba[1, 9] = new byte[] { 66, 45, 25, 102, 197, 189, 23, 18, 22 };
ModesProba[2, 0] = new byte[] { 88, 88, 147, 150, 42, 46, 45, 196, 205 };
ModesProba[2, 1] = new byte[] { 43, 97, 183, 117, 85, 38, 35, 179, 61 };
ModesProba[2, 2] = new byte[] { 39, 53, 200, 87, 26, 21, 43, 232, 171 };
ModesProba[2, 3] = new byte[] { 56, 34, 51, 104, 114, 102, 29, 93, 77 };
ModesProba[2, 4] = new byte[] { 39, 28, 85, 171, 58, 165, 90, 98, 64 };
ModesProba[2, 5] = new byte[] { 34, 22, 116, 206, 23, 34, 43, 166, 73 };
ModesProba[2, 6] = new byte[] { 107, 54, 32, 26, 51, 1, 81, 43, 31 };
ModesProba[2, 7] = new byte[] { 68, 25, 106, 22, 64, 171, 36, 225, 114 };
ModesProba[2, 8] = new byte[] { 34, 19, 21, 102, 132, 188, 16, 76, 124 };
ModesProba[2, 9] = new byte[] { 62, 18, 78, 95, 85, 57, 50, 48, 51 };
ModesProba[3, 0] = new byte[] { 193, 101, 35, 159, 215, 111, 89, 46, 111 };
ModesProba[3, 1] = new byte[] { 60, 148, 31, 172, 219, 228, 21, 18, 111 };
ModesProba[3, 2] = new byte[] { 112, 113, 77, 85, 179, 255, 38, 120, 114 };
ModesProba[3, 3] = new byte[] { 40, 42, 1, 196, 245, 209, 10, 25, 109 };
ModesProba[3, 4] = new byte[] { 88, 43, 29, 140, 166, 213, 37, 43, 154 };
ModesProba[3, 5] = new byte[] { 61, 63, 30, 155, 67, 45, 68, 1, 209 };
ModesProba[3, 6] = new byte[] { 100, 80, 8, 43, 154, 1, 51, 26, 71 };
ModesProba[3, 7] = new byte[] { 142, 78, 78, 16, 255, 128, 34, 197, 171 };
ModesProba[3, 8] = new byte[] { 41, 40, 5, 102, 211, 183, 4, 1, 221 };
ModesProba[3, 9] = new byte[] { 51, 50, 17, 168, 209, 192, 23, 25, 82 };
ModesProba[4, 0] = new byte[] { 138, 31, 36, 171, 27, 166, 38, 44, 229 };
ModesProba[4, 1] = new byte[] { 67, 87, 58, 169, 82, 115, 26, 59, 179 };
ModesProba[4, 2] = new byte[] { 63, 59, 90, 180, 59, 166, 93, 73, 154 };
ModesProba[4, 3] = new byte[] { 40, 40, 21, 116, 143, 209, 34, 39, 175 };
ModesProba[4, 4] = new byte[] { 47, 15, 16, 183, 34, 223, 49, 45, 183 };
ModesProba[4, 5] = new byte[] { 46, 17, 33, 183, 6, 98, 15, 32, 183 };
ModesProba[4, 6] = new byte[] { 57, 46, 22, 24, 128, 1, 54, 17, 37 };
ModesProba[4, 7] = new byte[] { 65, 32, 73, 115, 28, 128, 23, 128, 205 };
ModesProba[4, 8] = new byte[] { 40, 3, 9, 115, 51, 192, 18, 6, 223 };
ModesProba[4, 9] = new byte[] { 87, 37, 9, 115, 59, 77, 64, 21, 47 };
ModesProba[5, 0] = new byte[] { 104, 55, 44, 218, 9, 54, 53, 130, 226 };
ModesProba[5, 1] = new byte[] { 64, 90, 70, 205, 40, 41, 23, 26, 57 };
ModesProba[5, 2] = new byte[] { 54, 57, 112, 184, 5, 41, 38, 166, 213 };
ModesProba[5, 3] = new byte[] { 30, 34, 26, 133, 152, 116, 10, 32, 134 };
ModesProba[5, 4] = new byte[] { 39, 19, 53, 221, 26, 114, 32, 73, 255 };
ModesProba[5, 5] = new byte[] { 31, 9, 65, 234, 2, 15, 1, 118, 73 };
ModesProba[5, 6] = new byte[] { 75, 32, 12, 51, 192, 255, 160, 43, 51 };
ModesProba[5, 7] = new byte[] { 88, 31, 35, 67, 102, 85, 55, 186, 85 };
ModesProba[5, 8] = new byte[] { 56, 21, 23, 111, 59, 205, 45, 37, 192 };
ModesProba[5, 9] = new byte[] { 55, 38, 70, 124, 73, 102, 1, 34, 98 };
ModesProba[6, 0] = new byte[] { 125, 98, 42, 88, 104, 85, 117, 175, 82 };
ModesProba[6, 1] = new byte[] { 95, 84, 53, 89, 128, 100, 113, 101, 45 };
ModesProba[6, 2] = new byte[] { 75, 79, 123, 47, 51, 128, 81, 171, 1 };
ModesProba[6, 3] = new byte[] { 57, 17, 5, 71, 102, 57, 53, 41, 49 };
ModesProba[6, 4] = new byte[] { 38, 33, 13, 121, 57, 73, 26, 1, 85 };
ModesProba[6, 5] = new byte[] { 41, 10, 67, 138, 77, 110, 90, 47, 114 };
ModesProba[6, 6] = new byte[] { 115, 21, 2, 10, 102, 255, 166, 23, 6 };
ModesProba[6, 7] = new byte[] { 101, 29, 16, 10, 85, 128, 101, 196, 26 };
ModesProba[6, 8] = new byte[] { 57, 18, 10, 102, 102, 213, 34, 20, 43 };
ModesProba[6, 9] = new byte[] { 117, 20, 15, 36, 163, 128, 68, 1, 26 };
ModesProba[7, 0] = new byte[] { 102, 61, 71, 37, 34, 53, 31, 243, 192 };
ModesProba[7, 1] = new byte[] { 69, 60, 71, 38, 73, 119, 28, 222, 37 };
ModesProba[7, 2] = new byte[] { 68, 45, 128, 34, 1, 47, 11, 245, 171 };
ModesProba[7, 3] = new byte[] { 62, 17, 19, 70, 146, 85, 55, 62, 70 };
ModesProba[7, 4] = new byte[] { 37, 43, 37, 154, 100, 163, 85, 160, 1 };
ModesProba[7, 5] = new byte[] { 63, 9, 92, 136, 28, 64, 32, 201, 85 };
ModesProba[7, 6] = new byte[] { 75, 15, 9, 9, 64, 255, 184, 119, 16 };
ModesProba[7, 7] = new byte[] { 86, 6, 28, 5, 64, 255, 25, 248, 1 };
ModesProba[7, 8] = new byte[] { 56, 8, 17, 132, 137, 255, 55, 116, 128 };
ModesProba[7, 9] = new byte[] { 58, 15, 20, 82, 135, 57, 26, 121, 40 };
ModesProba[8, 0] = new byte[] { 164, 50, 31, 137, 154, 133, 25, 35, 218 };
ModesProba[8, 1] = new byte[] { 51, 103, 44, 131, 131, 123, 31, 6, 158 };
ModesProba[8, 2] = new byte[] { 86, 40, 64, 135, 148, 224, 45, 183, 128 };
ModesProba[8, 3] = new byte[] { 22, 26, 17, 131, 240, 154, 14, 1, 209 };
ModesProba[8, 4] = new byte[] { 45, 16, 21, 91, 64, 222, 7, 1, 197 };
ModesProba[8, 5] = new byte[] { 56, 21, 39, 155, 60, 138, 23, 102, 213 };
ModesProba[8, 6] = new byte[] { 83, 12, 13, 54, 192, 255, 68, 47, 28 };
ModesProba[8, 7] = new byte[] { 85, 26, 85, 85, 128, 128, 32, 146, 171 };
ModesProba[8, 8] = new byte[] { 18, 11, 7, 63, 144, 171, 4, 4, 246 };
ModesProba[8, 9] = new byte[] { 35, 27, 10, 146, 174, 171, 12, 26, 128 };
ModesProba[9, 0] = new byte[] { 190, 80, 35, 99, 180, 80, 126, 54, 45 };
ModesProba[9, 1] = new byte[] { 85, 126, 47, 87, 176, 51, 41, 20, 32 };
ModesProba[9, 2] = new byte[] { 101, 75, 128, 139, 118, 146, 116, 128, 85 };
ModesProba[9, 3] = new byte[] { 56, 41, 15, 176, 236, 85, 37, 9, 62 };
ModesProba[9, 4] = new byte[] { 71, 30, 17, 119, 118, 255, 17, 18, 138 };
ModesProba[9, 5] = new byte[] { 101, 38, 60, 138, 55, 70, 43, 26, 142 };
ModesProba[9, 6] = new byte[] { 146, 36, 19, 30, 171, 255, 97, 27, 20 };
ModesProba[9, 7] = new byte[] { 138, 45, 61, 62, 219, 1, 81, 188, 64 };
ModesProba[9, 8] = new byte[] { 32, 41, 20, 117, 151, 142, 20, 21, 163 };
ModesProba[9, 9] = new byte[] { 112, 19, 12, 61, 195, 128, 48, 4, 24 };
}
}
}

7
src/ImageSharp/Formats/WebP/Vp8MacroBlockData.cs

@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
public bool IsI4x4 { get; set; }
/// <summary>
/// Gets or sets the modes. One 16x16 mode (#0) or sixteen 4x4 modes.
/// Gets the modes. One 16x16 mode (#0) or sixteen 4x4 modes.
/// </summary>
public byte[] Modes { get; }
@ -38,11 +38,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
public uint NonZeroUv { get; set; }
/// <summary>
/// Gets or sets the local dithering strength (deduced from NonZero_*).
/// </summary>
public byte Dither { get; set; }
public byte Skip { get; set; }
public byte Segment { get; set; }

108
src/ImageSharp/Formats/WebP/WebPDecoderBase.cs

@ -1,108 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.WebP
{
abstract class WebPDecoderBase
{
protected HTreeGroup[] GetHTreeGroupForPos(Vp8LMetadata metadata, int x, int y)
{
uint metaIndex = this.GetMetaIndex(metadata.HuffmanImage, metadata.HuffmanXSize, metadata.HuffmanSubSampleBits, x, y);
return metadata.HTreeGroups.AsSpan((int)metaIndex).ToArray();
}
private uint GetMetaIndex(IMemoryOwner<uint> huffmanImage, int xSize, int bits, int x, int y)
{
if (bits is 0)
{
return 0;
}
Span<uint> huffmanImageSpan = huffmanImage.GetSpan();
return huffmanImageSpan[(xSize * (y >> bits)) + (x >> bits)];
}
/// <summary>
/// Decodes the next Huffman code from bit-stream.
/// FillBitWindow(br) needs to be called at minimum every second call
/// to ReadSymbol, in order to pre-fetch enough bits.
/// </summary>
protected uint ReadSymbol(Span<HuffmanCode> table, Vp8LBitReader bitReader)
{
// TODO: if the bitReader field is moved to this base class we could omit the parameter.
uint val = (uint)bitReader.PrefetchBits();
Span<HuffmanCode> tableSpan = table.Slice((int)(val & HuffmanUtils.HuffmanTableMask));
int nBits = tableSpan[0].BitsUsed - HuffmanUtils.HuffmanTableBits;
if (nBits > 0)
{
bitReader.AdvanceBitPosition(HuffmanUtils.HuffmanTableBits);
val = (uint)bitReader.PrefetchBits();
tableSpan = tableSpan.Slice((int)tableSpan[0].Value);
tableSpan = tableSpan.Slice((int)val & ((1 << nBits) - 1));
}
bitReader.AdvanceBitPosition(tableSpan[0].BitsUsed);
return tableSpan[0].Value;
}
protected int GetCopyDistance(int distanceSymbol, Vp8LBitReader bitReader)
{
if (distanceSymbol < 4)
{
return distanceSymbol + 1;
}
int extraBits = (distanceSymbol - 2) >> 1;
int offset = (2 + (distanceSymbol & 1)) << extraBits;
return (int)(offset + bitReader.ReadValue(extraBits) + 1);
}
protected int GetCopyLength(int lengthSymbol, Vp8LBitReader bitReader)
{
// Length and distance prefixes are encoded the same way.
return this.GetCopyDistance(lengthSymbol, bitReader);
}
// TODO: copied from LosslessDecoder
protected static readonly int[] KCodeToPlane =
{
0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70
};
protected static readonly int CodeToPlaneCodes = KCodeToPlane.Length;
protected int PlaneCodeToDistance(int xSize, int planeCode)
{
if (planeCode > CodeToPlaneCodes)
{
return planeCode - CodeToPlaneCodes;
}
int distCode = KCodeToPlane[planeCode - 1];
int yOffset = distCode >> 4;
int xOffset = 8 - (distCode & 0xf);
int dist = (yOffset * xSize) + xOffset;
// dist < 1 can happen if xSize is very small.
return (dist >= 1) ? dist : 1;
}
}
}

580
src/ImageSharp/Formats/WebP/WebPLookupTables.cs

@ -0,0 +1,580 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
namespace SixLabors.ImageSharp.Formats.WebP
{
internal static class WebPLookupTables
{
public static readonly Dictionary<int, byte> Abs0;
public static readonly Dictionary<int, byte> Clip1;
public static readonly Dictionary<int, sbyte> Sclip1;
public static readonly Dictionary<int, sbyte> Sclip2;
public static readonly byte[,][] ModesProba = new byte[10, 10][];
public static readonly int[] CodeToPlane =
{
0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70
};
// 31 ^ clz(i)
public static readonly byte[] LogTable8bit =
{
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
// Paragraph 14.1
public static readonly int[] DcTable =
{
4, 5, 6, 7, 8, 9, 10, 10,
11, 12, 13, 14, 15, 16, 17, 17,
18, 19, 20, 20, 21, 21, 22, 22,
23, 23, 24, 25, 25, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36,
37, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 76, 77, 78, 79, 80, 81,
82, 83, 84, 85, 86, 87, 88, 89,
91, 93, 95, 96, 98, 100, 101, 102,
104, 106, 108, 110, 112, 114, 116, 118,
122, 124, 126, 128, 130, 132, 134, 136,
138, 140, 143, 145, 148, 151, 154, 157
};
// Paragraph 14.1
public static readonly int[] AcTable =
{
4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 60,
62, 64, 66, 68, 70, 72, 74, 76,
78, 80, 82, 84, 86, 88, 90, 92,
94, 96, 98, 100, 102, 104, 106, 108,
110, 112, 114, 116, 119, 122, 125, 128,
131, 134, 137, 140, 143, 146, 149, 152,
155, 158, 161, 164, 167, 170, 173, 177,
181, 185, 189, 193, 197, 201, 205, 209,
213, 217, 221, 225, 229, 234, 239, 245,
249, 254, 259, 264, 269, 274, 279, 284
};
// Paragraph 13
public static readonly byte[,,,] CoeffsUpdateProba =
{
{
{
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 },
{ 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
}
},
{
{
{ 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 },
{ 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 }
},
{
{ 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
}
},
{
{
{ 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 },
{ 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 }
},
{
{ 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
}
},
{
{
{ 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 },
{ 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
},
{
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
}
}
};
// Paragraph 13.5: Default Token Probability Table.
public static readonly byte[,,,] DefaultCoeffsProba =
{
{
{
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
},
{
{ 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 },
{ 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 },
{ 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 }
},
{
{ 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 },
{ 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 },
{ 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 },
},
{
{ 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 },
{ 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 },
{ 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 },
},
{
{ 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 },
{ 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 },
{ 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 }
},
{
{ 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 },
{ 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 },
{ 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 }
},
{
{ 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 },
{ 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 },
{ 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 }
},
{
{ 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
}
},
{
{
{ 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 },
{ 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 },
{ 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 }
},
{
{ 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 },
{ 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 },
{ 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 }
},
{
{ 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 },
{ 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 },
{ 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 }
},
{
{ 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 },
{ 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 },
{ 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 }
},
{
{ 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 },
{ 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 },
{ 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 }
},
{
{ 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 },
{ 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 },
{ 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 }
},
{
{ 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 },
{ 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 },
{ 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 }
},
{
{ 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 },
{ 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 }
}
},
{
{
{ 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 },
{ 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 },
{ 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 }
},
{
{ 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 },
{ 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 },
{ 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 }
},
{
{ 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 },
{ 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 },
{ 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 }
},
{
{ 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 },
{ 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 }
},
{
{ 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 },
{ 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
},
{
{ 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
},
{
{ 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 },
{ 55, 93, 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 }
}
},
{
{
{ 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 },
{ 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 },
{ 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 }
},
{
{ 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 },
{ 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 },
{ 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 }
},
{
{ 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 },
{ 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 },
{ 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 }
},
{
{ 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 },
{ 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 },
{ 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 }
},
{
{ 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 },
{ 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 },
{ 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 }
},
{
{ 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 },
{ 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 },
{ 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 }
},
{
{ 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 },
{ 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 },
{ 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 }
},
{
{ 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
}
}
};
static WebPLookupTables()
{
// TODO: maybe use hashset here
Abs0 = new Dictionary<int, byte>();
for (int i = -255; i <= 255; ++i)
{
Abs0[i] = (byte)((i < 0) ? -i : i);
}
Clip1 = new Dictionary<int, byte>();
for (int i = -255; i <= 255 + 255; ++i)
{
Clip1[i] = (byte)((i < 0) ? 0 : (i > 255) ? 255 : i);
}
Sclip1 = new Dictionary<int, sbyte>();
for (int i = -1020; i <= 1020; ++i)
{
Sclip1[i] = (sbyte)((i < -128) ? -128 : (i > 127) ? 127 : i);
}
Sclip2 = new Dictionary<int, sbyte>();
for (int i = -112; i <= 112; ++i)
{
Sclip2[i] = (sbyte)((i < -16) ? -16 : (i > 15) ? 15 : i);
}
InitializeModesProbabilities();
}
private static void InitializeModesProbabilities()
{
// Paragraph 11.5
ModesProba[0, 0] = new byte[] { 231, 120, 48, 89, 115, 113, 120, 152, 112 };
ModesProba[0, 1] = new byte[] { 152, 179, 64, 126, 170, 118, 46, 70, 95 };
ModesProba[0, 2] = new byte[] { 175, 69, 143, 80, 85, 82, 72, 155, 103 };
ModesProba[0, 3] = new byte[] { 56, 58, 10, 171, 218, 189, 17, 13, 152 };
ModesProba[0, 4] = new byte[] { 114, 26, 17, 163, 44, 195, 21, 10, 173 };
ModesProba[0, 5] = new byte[] { 121, 24, 80, 195, 26, 62, 44, 64, 85 };
ModesProba[0, 6] = new byte[] { 144, 71, 10, 38, 171, 213, 144, 34, 26 };
ModesProba[0, 7] = new byte[] { 170, 46, 55, 19, 136, 160, 33, 206, 71 };
ModesProba[0, 8] = new byte[] { 63, 20, 8, 114, 114, 208, 12, 9, 226 };
ModesProba[0, 9] = new byte[] { 81, 40, 11, 96, 182, 84, 29, 16, 36 };
ModesProba[1, 0] = new byte[] { 134, 183, 89, 137, 98, 101, 106, 165, 148 };
ModesProba[1, 1] = new byte[] { 72, 187, 100, 130, 157, 111, 32, 75, 80 };
ModesProba[1, 2] = new byte[] { 66, 102, 167, 99, 74, 62, 40, 234, 128 };
ModesProba[1, 3] = new byte[] { 41, 53, 9, 178, 241, 141, 26, 8, 107 };
ModesProba[1, 4] = new byte[] { 74, 43, 26, 146, 73, 166, 49, 23, 157 };
ModesProba[1, 5] = new byte[] { 65, 38, 105, 160, 51, 52, 31, 115, 128 };
ModesProba[1, 6] = new byte[] { 104, 79, 12, 27, 217, 255, 87, 17, 7 };
ModesProba[1, 7] = new byte[] { 87, 68, 71, 44, 114, 51, 15, 186, 23 };
ModesProba[1, 8] = new byte[] { 47, 41, 14, 110, 182, 183, 21, 17, 194 };
ModesProba[1, 9] = new byte[] { 66, 45, 25, 102, 197, 189, 23, 18, 22 };
ModesProba[2, 0] = new byte[] { 88, 88, 147, 150, 42, 46, 45, 196, 205 };
ModesProba[2, 1] = new byte[] { 43, 97, 183, 117, 85, 38, 35, 179, 61 };
ModesProba[2, 2] = new byte[] { 39, 53, 200, 87, 26, 21, 43, 232, 171 };
ModesProba[2, 3] = new byte[] { 56, 34, 51, 104, 114, 102, 29, 93, 77 };
ModesProba[2, 4] = new byte[] { 39, 28, 85, 171, 58, 165, 90, 98, 64 };
ModesProba[2, 5] = new byte[] { 34, 22, 116, 206, 23, 34, 43, 166, 73 };
ModesProba[2, 6] = new byte[] { 107, 54, 32, 26, 51, 1, 81, 43, 31 };
ModesProba[2, 7] = new byte[] { 68, 25, 106, 22, 64, 171, 36, 225, 114 };
ModesProba[2, 8] = new byte[] { 34, 19, 21, 102, 132, 188, 16, 76, 124 };
ModesProba[2, 9] = new byte[] { 62, 18, 78, 95, 85, 57, 50, 48, 51 };
ModesProba[3, 0] = new byte[] { 193, 101, 35, 159, 215, 111, 89, 46, 111 };
ModesProba[3, 1] = new byte[] { 60, 148, 31, 172, 219, 228, 21, 18, 111 };
ModesProba[3, 2] = new byte[] { 112, 113, 77, 85, 179, 255, 38, 120, 114 };
ModesProba[3, 3] = new byte[] { 40, 42, 1, 196, 245, 209, 10, 25, 109 };
ModesProba[3, 4] = new byte[] { 88, 43, 29, 140, 166, 213, 37, 43, 154 };
ModesProba[3, 5] = new byte[] { 61, 63, 30, 155, 67, 45, 68, 1, 209 };
ModesProba[3, 6] = new byte[] { 100, 80, 8, 43, 154, 1, 51, 26, 71 };
ModesProba[3, 7] = new byte[] { 142, 78, 78, 16, 255, 128, 34, 197, 171 };
ModesProba[3, 8] = new byte[] { 41, 40, 5, 102, 211, 183, 4, 1, 221 };
ModesProba[3, 9] = new byte[] { 51, 50, 17, 168, 209, 192, 23, 25, 82 };
ModesProba[4, 0] = new byte[] { 138, 31, 36, 171, 27, 166, 38, 44, 229 };
ModesProba[4, 1] = new byte[] { 67, 87, 58, 169, 82, 115, 26, 59, 179 };
ModesProba[4, 2] = new byte[] { 63, 59, 90, 180, 59, 166, 93, 73, 154 };
ModesProba[4, 3] = new byte[] { 40, 40, 21, 116, 143, 209, 34, 39, 175 };
ModesProba[4, 4] = new byte[] { 47, 15, 16, 183, 34, 223, 49, 45, 183 };
ModesProba[4, 5] = new byte[] { 46, 17, 33, 183, 6, 98, 15, 32, 183 };
ModesProba[4, 6] = new byte[] { 57, 46, 22, 24, 128, 1, 54, 17, 37 };
ModesProba[4, 7] = new byte[] { 65, 32, 73, 115, 28, 128, 23, 128, 205 };
ModesProba[4, 8] = new byte[] { 40, 3, 9, 115, 51, 192, 18, 6, 223 };
ModesProba[4, 9] = new byte[] { 87, 37, 9, 115, 59, 77, 64, 21, 47 };
ModesProba[5, 0] = new byte[] { 104, 55, 44, 218, 9, 54, 53, 130, 226 };
ModesProba[5, 1] = new byte[] { 64, 90, 70, 205, 40, 41, 23, 26, 57 };
ModesProba[5, 2] = new byte[] { 54, 57, 112, 184, 5, 41, 38, 166, 213 };
ModesProba[5, 3] = new byte[] { 30, 34, 26, 133, 152, 116, 10, 32, 134 };
ModesProba[5, 4] = new byte[] { 39, 19, 53, 221, 26, 114, 32, 73, 255 };
ModesProba[5, 5] = new byte[] { 31, 9, 65, 234, 2, 15, 1, 118, 73 };
ModesProba[5, 6] = new byte[] { 75, 32, 12, 51, 192, 255, 160, 43, 51 };
ModesProba[5, 7] = new byte[] { 88, 31, 35, 67, 102, 85, 55, 186, 85 };
ModesProba[5, 8] = new byte[] { 56, 21, 23, 111, 59, 205, 45, 37, 192 };
ModesProba[5, 9] = new byte[] { 55, 38, 70, 124, 73, 102, 1, 34, 98 };
ModesProba[6, 0] = new byte[] { 125, 98, 42, 88, 104, 85, 117, 175, 82 };
ModesProba[6, 1] = new byte[] { 95, 84, 53, 89, 128, 100, 113, 101, 45 };
ModesProba[6, 2] = new byte[] { 75, 79, 123, 47, 51, 128, 81, 171, 1 };
ModesProba[6, 3] = new byte[] { 57, 17, 5, 71, 102, 57, 53, 41, 49 };
ModesProba[6, 4] = new byte[] { 38, 33, 13, 121, 57, 73, 26, 1, 85 };
ModesProba[6, 5] = new byte[] { 41, 10, 67, 138, 77, 110, 90, 47, 114 };
ModesProba[6, 6] = new byte[] { 115, 21, 2, 10, 102, 255, 166, 23, 6 };
ModesProba[6, 7] = new byte[] { 101, 29, 16, 10, 85, 128, 101, 196, 26 };
ModesProba[6, 8] = new byte[] { 57, 18, 10, 102, 102, 213, 34, 20, 43 };
ModesProba[6, 9] = new byte[] { 117, 20, 15, 36, 163, 128, 68, 1, 26 };
ModesProba[7, 0] = new byte[] { 102, 61, 71, 37, 34, 53, 31, 243, 192 };
ModesProba[7, 1] = new byte[] { 69, 60, 71, 38, 73, 119, 28, 222, 37 };
ModesProba[7, 2] = new byte[] { 68, 45, 128, 34, 1, 47, 11, 245, 171 };
ModesProba[7, 3] = new byte[] { 62, 17, 19, 70, 146, 85, 55, 62, 70 };
ModesProba[7, 4] = new byte[] { 37, 43, 37, 154, 100, 163, 85, 160, 1 };
ModesProba[7, 5] = new byte[] { 63, 9, 92, 136, 28, 64, 32, 201, 85 };
ModesProba[7, 6] = new byte[] { 75, 15, 9, 9, 64, 255, 184, 119, 16 };
ModesProba[7, 7] = new byte[] { 86, 6, 28, 5, 64, 255, 25, 248, 1 };
ModesProba[7, 8] = new byte[] { 56, 8, 17, 132, 137, 255, 55, 116, 128 };
ModesProba[7, 9] = new byte[] { 58, 15, 20, 82, 135, 57, 26, 121, 40 };
ModesProba[8, 0] = new byte[] { 164, 50, 31, 137, 154, 133, 25, 35, 218 };
ModesProba[8, 1] = new byte[] { 51, 103, 44, 131, 131, 123, 31, 6, 158 };
ModesProba[8, 2] = new byte[] { 86, 40, 64, 135, 148, 224, 45, 183, 128 };
ModesProba[8, 3] = new byte[] { 22, 26, 17, 131, 240, 154, 14, 1, 209 };
ModesProba[8, 4] = new byte[] { 45, 16, 21, 91, 64, 222, 7, 1, 197 };
ModesProba[8, 5] = new byte[] { 56, 21, 39, 155, 60, 138, 23, 102, 213 };
ModesProba[8, 6] = new byte[] { 83, 12, 13, 54, 192, 255, 68, 47, 28 };
ModesProba[8, 7] = new byte[] { 85, 26, 85, 85, 128, 128, 32, 146, 171 };
ModesProba[8, 8] = new byte[] { 18, 11, 7, 63, 144, 171, 4, 4, 246 };
ModesProba[8, 9] = new byte[] { 35, 27, 10, 146, 174, 171, 12, 26, 128 };
ModesProba[9, 0] = new byte[] { 190, 80, 35, 99, 180, 80, 126, 54, 45 };
ModesProba[9, 1] = new byte[] { 85, 126, 47, 87, 176, 51, 41, 20, 32 };
ModesProba[9, 2] = new byte[] { 101, 75, 128, 139, 118, 146, 116, 128, 85 };
ModesProba[9, 3] = new byte[] { 56, 41, 15, 176, 236, 85, 37, 9, 62 };
ModesProba[9, 4] = new byte[] { 71, 30, 17, 119, 118, 255, 17, 18, 138 };
ModesProba[9, 5] = new byte[] { 101, 38, 60, 138, 55, 70, 43, 26, 142 };
ModesProba[9, 6] = new byte[] { 146, 36, 19, 30, 171, 255, 97, 27, 20 };
ModesProba[9, 7] = new byte[] { 138, 45, 61, 62, 219, 1, 81, 188, 64 };
ModesProba[9, 8] = new byte[] { 32, 41, 20, 117, 151, 142, 20, 21, 163 };
ModesProba[9, 9] = new byte[] { 112, 19, 12, 61, 195, 128, 48, 4, 24 };
}
}
}

108
src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// The lossless specification can be found here:
/// https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification
/// </remarks>
internal sealed class WebPLosslessDecoder : WebPDecoderBase
internal sealed class WebPLosslessDecoder
{
private readonly Vp8LBitReader bitReader;
@ -27,11 +27,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
private static readonly uint PackedNonLiteralCode = 0;
private static readonly int NumArgbCacheRows = 16;
private static readonly int CodeToPlaneCodes = WebPLookupTables.CodeToPlane.Length;
private static readonly int FixedTableSize = (630 * 3) + 410;
private static readonly int[] KTableSize =
private static readonly int[] TableSize =
{
FixedTableSize + 654,
FixedTableSize + 656,
@ -47,10 +47,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
FixedTableSize + 2704
};
private static readonly byte[] KCodeLengthCodeOrder = { 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
private static readonly int NumCodeLengthCodes = KCodeLengthCodeOrder.Length;
private static readonly byte[] CodeLengthCodeOrder = { 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
private static readonly byte[] KLiteralMap =
private static readonly int NumCodeLengthCodes = CodeLengthCodeOrder.Length;
private static readonly byte[] LiteralMap =
{
0, 1, 1, 1, 0
};
@ -235,7 +236,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
else
{
code = (int)this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Green], this.bitReader);
code = (int)this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Green]);
}
if (this.bitReader.IsEndOfStream())
@ -252,10 +253,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
else
{
uint red = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Red], this.bitReader);
uint red = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Red]);
this.bitReader.FillBitWindow();
uint blue = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Blue], this.bitReader);
uint alpha = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Alpha], this.bitReader);
uint blue = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Blue]);
uint alpha = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Alpha]);
if (this.bitReader.IsEndOfStream())
{
break;
@ -271,10 +272,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
// Backward reference is used.
int lengthSym = code - WebPConstants.NumLiteralCodes;
int length = this.GetCopyLength(lengthSym, this.bitReader);
uint distSymbol = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Dist], this.bitReader);
int length = this.GetCopyLength(lengthSym);
uint distSymbol = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Dist]);
this.bitReader.FillBitWindow();
int distCode = this.GetCopyDistance((int)distSymbol, this.bitReader);
int distCode = this.GetCopyDistance((int)distSymbol);
int dist = this.PlaneCodeToDistance(width, distCode);
if (this.bitReader.IsEndOfStream())
{
@ -392,7 +393,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
int tableSize = KTableSize[colorCacheBits];
int tableSize = TableSize[colorCacheBits];
var huffmanTables = new HuffmanCode[numHTreeGroups * tableSize];
var hTreeGroups = new HTreeGroup[numHTreeGroups];
Span<HuffmanCode> huffmanTable = huffmanTables.AsSpan();
@ -420,7 +421,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
hTreeGroup.HTrees.Add(huffmanTable.ToArray());
if (isTrivialLiteral && KLiteralMap[j] == 1)
if (isTrivialLiteral && LiteralMap[j] == 1)
{
isTrivialLiteral = huffmanTable[0].BitsUsed == 0;
}
@ -515,7 +516,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
for (int i = 0; i < numCodes; i++)
{
codeLengthCodeLengths[KCodeLengthCodeOrder[i]] = (int)this.bitReader.ReadValue(3);
codeLengthCodeLengths[CodeLengthCodeOrder[i]] = (int)this.bitReader.ReadValue(3);
}
this.ReadHuffmanCodeLengths(table.ToArray(), codeLengthCodeLengths, alphabetSize, codeLengths);
@ -750,6 +751,81 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
/// <summary>
/// Decodes the next Huffman code from bit-stream.
/// FillBitWindow(br) needs to be called at minimum every second call to ReadSymbol, in order to pre-fetch enough bits.
/// </summary>
private uint ReadSymbol(Span<HuffmanCode> table)
{
// TODO: if the bitReader field is moved to this base class we could omit the parameter.
uint val = (uint)this.bitReader.PrefetchBits();
Span<HuffmanCode> tableSpan = table.Slice((int)(val & HuffmanUtils.HuffmanTableMask));
int nBits = tableSpan[0].BitsUsed - HuffmanUtils.HuffmanTableBits;
if (nBits > 0)
{
this.bitReader.AdvanceBitPosition(HuffmanUtils.HuffmanTableBits);
val = (uint)this.bitReader.PrefetchBits();
tableSpan = tableSpan.Slice((int)tableSpan[0].Value);
tableSpan = tableSpan.Slice((int)val & ((1 << nBits) - 1));
}
this.bitReader.AdvanceBitPosition(tableSpan[0].BitsUsed);
return tableSpan[0].Value;
}
private HTreeGroup[] GetHTreeGroupForPos(Vp8LMetadata metadata, int x, int y)
{
uint metaIndex = this.GetMetaIndex(metadata.HuffmanImage, metadata.HuffmanXSize, metadata.HuffmanSubSampleBits, x, y);
return metadata.HTreeGroups.AsSpan((int)metaIndex).ToArray();
}
private uint GetMetaIndex(IMemoryOwner<uint> huffmanImage, int xSize, int bits, int x, int y)
{
if (bits is 0)
{
return 0;
}
Span<uint> huffmanImageSpan = huffmanImage.GetSpan();
return huffmanImageSpan[(xSize * (y >> bits)) + (x >> bits)];
}
private int PlaneCodeToDistance(int xSize, int planeCode)
{
if (planeCode > CodeToPlaneCodes)
{
return planeCode - CodeToPlaneCodes;
}
int distCode = WebPLookupTables.CodeToPlane[planeCode - 1];
int yOffset = distCode >> 4;
int xOffset = 8 - (distCode & 0xf);
int dist = (yOffset * xSize) + xOffset;
// dist < 1 can happen if xSize is very small.
return (dist >= 1) ? dist : 1;
}
private int GetCopyDistance(int distanceSymbol)
{
if (distanceSymbol < 4)
{
return distanceSymbol + 1;
}
int extraBits = (distanceSymbol - 2) >> 1;
int offset = (2 + (distanceSymbol & 1)) << extraBits;
return (int)(offset + this.bitReader.ReadValue(extraBits) + 1);
}
private int GetCopyLength(int lengthSymbol)
{
// Length and distance prefixes are encoded the same way.
return this.GetCopyDistance(lengthSymbol);
}
private int AccumulateHCode(HuffmanCode hCode, int shift, HuffmanCode huff)
{
huff.BitsUsed += hCode.BitsUsed;

92
src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

@ -12,7 +12,7 @@ using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.WebP
{
internal sealed class WebPLossyDecoder : WebPDecoderBase
internal sealed class WebPLossyDecoder
{
private readonly Vp8BitReader bitReader;
@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
int yMode = left[y];
for (int x = 0; x < 4; ++x)
{
byte[] prob = Vp8LookupTables.ModesProba[top[x], yMode];
byte[] prob = WebPLookupTables.ModesProba[top[x], yMode];
int i = WebPConstants.YModesIntra4[this.bitReader.GetBit(prob[0])];
while (i > 0)
{
@ -328,34 +328,34 @@ namespace SixLabors.ImageSharp.Formats.WebP
switch (lumaMode)
{
case 0:
LossyUtils.DC4_C(dst, yuv, offset);
LossyUtils.DC4(dst, yuv, offset);
break;
case 1:
LossyUtils.TM4_C(dst, yuv, offset);
LossyUtils.TM4(dst, yuv, offset);
break;
case 2:
LossyUtils.VE4_C(dst, yuv, offset);
LossyUtils.VE4(dst, yuv, offset);
break;
case 3:
LossyUtils.HE4_C(dst, yuv, offset);
LossyUtils.HE4(dst, yuv, offset);
break;
case 4:
LossyUtils.RD4_C(dst, yuv, offset);
LossyUtils.RD4(dst, yuv, offset);
break;
case 5:
LossyUtils.VR4_C(dst, yuv, offset);
LossyUtils.VR4(dst, yuv, offset);
break;
case 6:
LossyUtils.LD4_C(dst, yuv, offset);
LossyUtils.LD4(dst, yuv, offset);
break;
case 7:
LossyUtils.VL4_C(dst, yuv, offset);
LossyUtils.VL4(dst, yuv, offset);
break;
case 8:
LossyUtils.HD4_C(dst, yuv, offset);
LossyUtils.HD4(dst, yuv, offset);
break;
case 9:
LossyUtils.HU4_C(dst, yuv, offset);
LossyUtils.HU4(dst, yuv, offset);
break;
}
@ -369,25 +369,25 @@ namespace SixLabors.ImageSharp.Formats.WebP
switch (mode)
{
case 0:
LossyUtils.DC16_C(yDst, yuv, yOff);
LossyUtils.DC16(yDst, yuv, yOff);
break;
case 1:
LossyUtils.TM16_C(yDst, yuv, yOff);
LossyUtils.TM16(yDst, yuv, yOff);
break;
case 2:
LossyUtils.VE16_C(yDst, yuv, yOff);
LossyUtils.VE16(yDst, yuv, yOff);
break;
case 3:
LossyUtils.HE16_C(yDst, yuv, yOff);
LossyUtils.HE16(yDst, yuv, yOff);
break;
case 4:
LossyUtils.DC16NoTop_C(yDst, yuv, yOff);
LossyUtils.DC16NoTop(yDst, yuv, yOff);
break;
case 5:
LossyUtils.DC16NoLeft_C(yDst, yuv, yOff);
LossyUtils.DC16NoLeft(yDst, yuv, yOff);
break;
case 6:
LossyUtils.DC16NoTopLeft_C(yDst);
LossyUtils.DC16NoTopLeft(yDst);
break;
}
@ -406,32 +406,32 @@ namespace SixLabors.ImageSharp.Formats.WebP
switch (chromaMode)
{
case 0:
LossyUtils.DC8uv_C(uDst, yuv, uOff);
LossyUtils.DC8uv_C(vDst, yuv, vOff);
LossyUtils.DC8uv(uDst, yuv, uOff);
LossyUtils.DC8uv(vDst, yuv, vOff);
break;
case 1:
LossyUtils.TM8uv_C(uDst, yuv, uOff);
LossyUtils.TM8uv_C(vDst, yuv, vOff);
LossyUtils.TM8uv(uDst, yuv, uOff);
LossyUtils.TM8uv(vDst, yuv, vOff);
break;
case 2:
LossyUtils.VE8uv_C(uDst, yuv, uOff);
LossyUtils.VE8uv_C(vDst, yuv, vOff);
LossyUtils.VE8uv(uDst, yuv, uOff);
LossyUtils.VE8uv(vDst, yuv, vOff);
break;
case 3:
LossyUtils.HE8uv_C(uDst, yuv, uOff);
LossyUtils.HE8uv_C(vDst, yuv, vOff);
LossyUtils.HE8uv(uDst, yuv, uOff);
LossyUtils.HE8uv(vDst, yuv, vOff);
break;
case 4:
LossyUtils.DC8uvNoTop_C(uDst, yuv, uOff);
LossyUtils.DC8uvNoTop_C(vDst, yuv, vOff);
LossyUtils.DC8uvNoTop(uDst, yuv, uOff);
LossyUtils.DC8uvNoTop(vDst, yuv, vOff);
break;
case 5:
LossyUtils.DC8uvNoLeft_C(uDst, yuv, uOff);
LossyUtils.DC8uvNoLeft_C(vDst, yuv, vOff);
LossyUtils.DC8uvNoLeft(uDst, yuv, uOff);
LossyUtils.DC8uvNoLeft(vDst, yuv, vOff);
break;
case 6:
LossyUtils.DC8uvNoTopLeft_C(uDst);
LossyUtils.DC8uvNoTopLeft_C(vDst);
LossyUtils.DC8uvNoTopLeft(uDst);
LossyUtils.DC8uvNoTopLeft(vDst);
break;
}
@ -803,7 +803,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
blockData.NonZeroY = 0;
blockData.NonZeroUv = 0;
blockData.Dither = 0;
}
// Store filter info.
@ -921,10 +920,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
block.NonZeroY = nonZeroY;
block.NonZeroUv = nonZeroUv;
// We look at the mode-code of each block and check if some blocks have less
// than three non-zero coeffs (code < 2). This is to avoid dithering flat and empty blocks.
block.Dither = (byte)((nonZeroUv & 0xaaaa) > 0 ? 0 : q.Dither);
return (nonZeroY | nonZeroUv) is 0;
}
@ -1227,20 +1222,20 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
Vp8QuantMatrix m = decoder.DeQuantMatrices[i];
m.Y1Mat[0] = Vp8LookupTables.DcTable[Clip(q + dqy1Dc, 127)];
m.Y1Mat[1] = Vp8LookupTables.AcTable[Clip(q + 0, 127)];
m.Y2Mat[0] = Vp8LookupTables.DcTable[Clip(q + dqy2Dc, 127)] * 2;
m.Y1Mat[0] = WebPLookupTables.DcTable[Clip(q + dqy1Dc, 127)];
m.Y1Mat[1] = WebPLookupTables.AcTable[Clip(q + 0, 127)];
m.Y2Mat[0] = WebPLookupTables.DcTable[Clip(q + dqy2Dc, 127)] * 2;
// For all x in [0..284], x*155/100 is bitwise equal to (x*101581) >> 16.
// The smallest precision for that is '(x*6349) >> 12' but 16 is a good word size.
m.Y2Mat[1] = (Vp8LookupTables.AcTable[Clip(q + dqy2Ac, 127)] * 101581) >> 16;
m.Y2Mat[1] = (WebPLookupTables.AcTable[Clip(q + dqy2Ac, 127)] * 101581) >> 16;
if (m.Y2Mat[1] < 8)
{
m.Y2Mat[1] = 8;
}
m.UvMat[0] = Vp8LookupTables.DcTable[Clip(q + dquvDc, 117)];
m.UvMat[1] = Vp8LookupTables.AcTable[Clip(q + dquvAc, 127)];
m.UvMat[0] = WebPLookupTables.DcTable[Clip(q + dquvDc, 117)];
m.UvMat[1] = WebPLookupTables.AcTable[Clip(q + dquvAc, 127)];
// For dithering strength evaluation.
m.UvQuant = q + dquvAc;
@ -1259,10 +1254,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
for (int p = 0; p < WebPConstants.NumProbas; ++p)
{
byte prob = Vp8LookupTables.CoeffsUpdateProba[t, b, c, p];
byte prob = WebPLookupTables.CoeffsUpdateProba[t, b, c, p];
int v = this.bitReader.GetBit(prob) != 0
? (int)this.bitReader.ReadValue(8)
: Vp8LookupTables.DefaultCoeffsProba[t, b, c, p];
: WebPLookupTables.DefaultCoeffsProba[t, b, c, p];
proba.Bands[t, b].Probabilities[c].Probabilities[p] = (byte)v;
}
}
@ -1343,9 +1338,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
return io;
}
static bool Is8bOptimizable(Vp8LMetadata hdr)
private static bool Is8bOptimizable(Vp8LMetadata hdr)
{
int i;
if (hdr.ColorCacheSize > 0)
{
return false;
@ -1353,7 +1347,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
// When the Huffman tree contains only one symbol, we can skip the
// call to ReadSymbol() for red/blue/alpha channels.
for (i = 0; i < hdr.NumHTreeGroups; ++i)
for (int i = 0; i < hdr.NumHTreeGroups; ++i)
{
List<HuffmanCode[]> htrees = hdr.HTreeGroups[i].HTrees;
if (htrees[HuffIndex.Red][0].Value > 0)

4
tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs

@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
}
}
[Benchmark(Baseline = true, Description = "Magick Lossy WebP")]
[Benchmark(Description = "Magick Lossy WebP")]
public int WebpLossyMagick()
{
var settings = new MagickReadSettings { Format = MagickFormat.WebP };
@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
}
}
[Benchmark(Baseline = true, Description = "Magick Lossless WebP")]
[Benchmark(Description = "Magick Lossless WebP")]
public int WebpLosslessMagick()
{
var settings = new MagickReadSettings { Format = MagickFormat.WebP };

8
tests/ImageSharp.Tests/Formats/WebP/WebPDecoderTests.cs

@ -21,11 +21,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP
private static MagickReferenceDecoder ReferenceDecoder => new MagickReferenceDecoder();
[Theory]
[InlineData(Lossless.Lossless1, 1000, 307, 24)]
[InlineData(Lossless.Lossless2, 1000, 307, 24)]
[InlineData(Lossless.GreenTransform1, 1000, 307, 32)]
[InlineData(Lossless.BikeThreeTransforms, 250, 195, 32)]
[InlineData(Lossless.NoTransform2, 128, 128, 32)]
[InlineData(Lossy.Alpha1, 1000, 307, 32)]
[InlineData(Lossy.Alpha2, 1000, 307, 32)]
public void Identify_DetectsCorrectDimensions(
[InlineData(Lossy.Bike, 250, 195, 24)]
public void Identify_DetectsCorrectDimensionsAndBitDepth(
string imagePath,
int expectedWidth,
int expectedHeight,

19
tests/ImageSharp.Tests/Formats/WebP/WebPMetaDataTests.cs

@ -12,8 +12,7 @@ using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.WebP
{
using static SixLabors.ImageSharp.Tests.TestImages.WebP;
using static TestImages.Bmp;
public class WebPMetaDataTests
{
[Fact]
@ -27,21 +26,5 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP
Assert.False(meta.BitsPerPixel.Equals(clone.BitsPerPixel));*/
}
[Theory]
[InlineData(Lossless.Lossless1, BmpInfoHeaderType.WinVersion2)]
public void Identify_DetectsCorrectBitmapInfoHeaderType(string imagePath, BmpInfoHeaderType expectedInfoHeaderType)
{
var testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false))
{
IImageInfo imageInfo = Image.Identify(stream);
Assert.NotNull(imageInfo);
Assert.Equal(24, imageInfo.PixelType.BitsPerPixel);
//var webpMetaData = imageInfo.Metadata.GetFormatMetadata(WebPFormat.Instance);
//Assert.NotNull(webpMetaData);
//Assert.Equal(expectedInfoHeaderType, webpMetaData.InfoHeaderType);
}
}
}
}

7
tests/ImageSharp.Tests/TestImages.cs

@ -378,8 +378,6 @@ namespace SixLabors.ImageSharp.Tests
public static class Lossless
{
public const string Lossless1 = "WebP/lossless1.webp";
public const string Lossless2 = "WebP/lossless2.webp";
public const string NoTransform1 = "WebP/lossless_vec_1_0.webp";
public const string NoTransform2 = "WebP/lossless_vec_2_0.webp";
public const string GreenTransform1 = "WebP/lossless1.webp";
@ -498,11 +496,6 @@ namespace SixLabors.ImageSharp.Tests
public const string AlphaNoCompression = "WebP/alpha_no_compression.webp";
}
public static readonly string[] All =
{
Lossless.Lossless1
};
}
}
}

Loading…
Cancel
Save