mirror of https://github.com/SixLabors/ImageSharp
15 changed files with 250 additions and 638 deletions
@ -1,104 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using System; |
|
||||
using System.Diagnostics; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats.WebP.Filters |
|
||||
{ |
|
||||
// TODO from dsp.h
|
|
||||
// public enum WebPFilterType
|
|
||||
// {
|
|
||||
// None = 0,
|
|
||||
// Horizontal,
|
|
||||
// Vertical,
|
|
||||
// Gradient,
|
|
||||
// Last = Gradient + 1, // end marker
|
|
||||
// Best, // meta types
|
|
||||
// Fast
|
|
||||
// }
|
|
||||
|
|
||||
internal abstract class WebPFilterBase |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// </summary>
|
|
||||
/// <param name="prevLine"></param>
|
|
||||
/// <param name="prevLineOffset">nullable as prevLine is nullable in the original but Span'T can't be null.</param>
|
|
||||
/// <param name="preds"></param>
|
|
||||
/// <param name="predsOffset"></param>
|
|
||||
/// <param name="currentLine"></param>
|
|
||||
/// <param name="currentLineOffset"></param>
|
|
||||
/// <param name="width"></param>
|
|
||||
public abstract void Unfilter( |
|
||||
Span<byte> prevLine, |
|
||||
int? prevLineOffset, |
|
||||
Span<byte> preds, |
|
||||
int predsOffset, |
|
||||
Span<byte> currentLine, |
|
||||
int currentLineOffset, |
|
||||
int width); |
|
||||
|
|
||||
public abstract void Filter( |
|
||||
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) |
|
||||
{ |
|
||||
Debug.Assert(input != null); |
|
||||
Debug.Assert(output != null); |
|
||||
Debug.Assert(width > 0); |
|
||||
Debug.Assert(height > 0); |
|
||||
Debug.Assert(stride > width); |
|
||||
Debug.Assert(row >= 0); |
|
||||
Debug.Assert(height > 0); |
|
||||
Debug.Assert(row + numRows <= height); |
|
||||
} |
|
||||
|
|
||||
protected static void PredictLine( |
|
||||
Span<byte> src, |
|
||||
int srcOffset, |
|
||||
Span<byte> pred, |
|
||||
int predOffset, |
|
||||
Span<byte> dst, |
|
||||
int dstOffset, |
|
||||
int length, |
|
||||
bool inverse) |
|
||||
{ |
|
||||
if (inverse) |
|
||||
{ |
|
||||
for (int i = 0; i < length; i++) |
|
||||
{ |
|
||||
dst[i] = (byte)(src[i] + pred[i]); |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
for (int i = 0; i < length; i++) |
|
||||
{ |
|
||||
dst[i] = (byte)(src[i] - pred[i]); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected void UnfilterHorizontalOrVerticalCore( |
|
||||
byte pred, |
|
||||
Span<byte> input, |
|
||||
int inputOffset, |
|
||||
Span<byte> output, |
|
||||
int outputOffset, |
|
||||
int width) |
|
||||
{ |
|
||||
for (int i = 0; i < width; i++) |
|
||||
{ |
|
||||
output[outputOffset + i] = (byte)(pred + input[inputOffset + i]); |
|
||||
pred = output[i]; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,116 +0,0 @@ |
|||||
// 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, |
|
||||
Span<byte> input, |
|
||||
int inputOffset, |
|
||||
Span<byte> output, |
|
||||
int outputOffset, |
|
||||
int width) |
|
||||
{ |
|
||||
if (prevLineOffsetNullable is int prevLineOffset) |
|
||||
{ |
|
||||
byte top = prevLine[prevLineOffset]; |
|
||||
byte topLeft = top; |
|
||||
byte left = top; |
|
||||
for (int i = 0; i < width; i++) |
|
||||
{ |
|
||||
top = prevLine[prevLineOffset + i]; // need to read this first in case prev==out
|
|
||||
left = (byte)(input[inputOffset + i] + GradientPredictor(left, top, topLeft)); |
|
||||
topLeft = top; |
|
||||
output[outputOffset + i] = left; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
this.UnfilterHorizontalOrVerticalCore(0, 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) |
|
||||
{ |
|
||||
// calling (input, width, height, stride, 0, height, 0, output
|
|
||||
int row = 0; |
|
||||
int numRows = height; |
|
||||
bool inverse = false; |
|
||||
|
|
||||
int startOffset = row * stride; |
|
||||
int lastRow = row + numRows; |
|
||||
SanityCheck(input, output, width, numRows, height, stride, row); |
|
||||
inputOffset += startOffset; |
|
||||
outputOffset += startOffset; |
|
||||
Span<byte> preds; |
|
||||
int predsOffset; |
|
||||
if (inverse) |
|
||||
{ |
|
||||
preds = output; |
|
||||
predsOffset = outputOffset; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
preds = input; |
|
||||
predsOffset = inputOffset; |
|
||||
} |
|
||||
|
|
||||
if (row == 0) |
|
||||
{ |
|
||||
output[outputOffset] = input[inputOffset]; |
|
||||
PredictLine( |
|
||||
input, |
|
||||
inputOffset + 1, |
|
||||
preds, |
|
||||
predsOffset, |
|
||||
output, |
|
||||
outputOffset + 1, |
|
||||
width - 1, |
|
||||
inverse); |
|
||||
} |
|
||||
|
|
||||
while (row < lastRow) |
|
||||
{ |
|
||||
PredictLine( |
|
||||
input, |
|
||||
inputOffset, |
|
||||
preds, |
|
||||
predsOffset - stride, |
|
||||
output, |
|
||||
outputOffset, |
|
||||
1, |
|
||||
inverse); |
|
||||
|
|
||||
for (int w = 1; w < width; w++) |
|
||||
{ |
|
||||
int pred = GradientPredictor(preds[w - 1], preds[w - stride], preds[w - stride - 1]); |
|
||||
int signedPred = inverse ? pred : -pred; |
|
||||
output[outputOffset + w] = (byte)(input[inputOffset + w] + signedPred); |
|
||||
} |
|
||||
|
|
||||
row++; |
|
||||
predsOffset += stride; |
|
||||
inputOffset += stride; |
|
||||
outputOffset += stride; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static int GradientPredictor(byte a, byte b, byte c) |
|
||||
{ |
|
||||
int g = a + b + c; |
|
||||
return (g & ~0xff) == 0 ? g : (g < 0) ? 0 : 255; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,115 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using System; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats.WebP.Filters |
|
||||
{ |
|
||||
internal class WebPFilterHorizontal : WebPFilterBase |
|
||||
{ |
|
||||
public override void Unfilter( |
|
||||
Span<byte> prevLine, |
|
||||
int? prevLineOffsetNullable, |
|
||||
Span<byte> input, |
|
||||
int inputOffset, |
|
||||
Span<byte> output, |
|
||||
int outputOffset, |
|
||||
int width) |
|
||||
{ |
|
||||
byte pred = prevLineOffsetNullable is int prevLineOffset |
|
||||
? prevLine[prevLineOffset] |
|
||||
: (byte)0; |
|
||||
|
|
||||
this.UnfilterHorizontalOrVerticalCore( |
|
||||
pred, |
|
||||
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) |
|
||||
{ |
|
||||
int numRows = height; |
|
||||
int row = 0; |
|
||||
|
|
||||
const bool inverse = false; |
|
||||
|
|
||||
int startOffset = row * stride; |
|
||||
int lastRow = row + height; |
|
||||
SanityCheck(input, output, width, height, numRows, stride, row); |
|
||||
inputOffset += startOffset; |
|
||||
outputOffset += startOffset; |
|
||||
|
|
||||
Span<byte> preds; |
|
||||
int predsOffset; |
|
||||
|
|
||||
if (inverse) |
|
||||
{ |
|
||||
preds = output; |
|
||||
predsOffset = outputOffset; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
preds = input; |
|
||||
predsOffset = inputOffset; |
|
||||
} |
|
||||
|
|
||||
if (row is 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); |
|
||||
|
|
||||
row = 1; |
|
||||
predsOffset += stride; |
|
||||
inputOffset += stride; |
|
||||
outputOffset += stride; |
|
||||
} |
|
||||
|
|
||||
// Filter line by line.
|
|
||||
while (row < lastRow) |
|
||||
{ |
|
||||
PredictLine( |
|
||||
input, |
|
||||
inputOffset, |
|
||||
preds, |
|
||||
predsOffset - stride, |
|
||||
output, |
|
||||
0, |
|
||||
1, |
|
||||
inverse); |
|
||||
PredictLine( |
|
||||
input, |
|
||||
inputOffset, |
|
||||
preds, |
|
||||
predsOffset, |
|
||||
output, |
|
||||
outputOffset + 1, |
|
||||
width - 1, |
|
||||
inverse); |
|
||||
|
|
||||
row++; |
|
||||
predsOffset += stride; |
|
||||
inputOffset += stride; |
|
||||
outputOffset += stride; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,33 +0,0 @@ |
|||||
// 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 Filter( |
|
||||
Span<byte> input, |
|
||||
int inputOffset, |
|
||||
int width, |
|
||||
int height, |
|
||||
int stride, |
|
||||
Span<byte> output, |
|
||||
int outputOffset) |
|
||||
{ |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,16 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats.WebP.Filters |
|
||||
{ |
|
||||
internal enum WebPFilterType |
|
||||
{ |
|
||||
None = 0, |
|
||||
|
|
||||
Horizontal = 1, |
|
||||
|
|
||||
Vertical = 2, |
|
||||
|
|
||||
Gradient = 3, |
|
||||
} |
|
||||
} |
|
||||
@ -1,100 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using System; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Formats.WebP.Filters |
|
||||
{ |
|
||||
class WebPFilterVertical : WebPFilterBase |
|
||||
{ |
|
||||
public override void Unfilter(Span<byte> prevLine, int? prevLineOffsetNullable, Span<byte> input, int inputOffset, Span<byte> output, int outputOffset, int width) |
|
||||
{ |
|
||||
if (prevLineOffsetNullable is int prevLineOffset) |
|
||||
{ |
|
||||
for (int i = 0; i < width; i++) |
|
||||
{ |
|
||||
output[outputOffset + i] = (byte)(prevLine[prevLineOffset + i] + input[inputOffset + i]); |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
this.UnfilterHorizontalOrVerticalCore(0, 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) |
|
||||
{ |
|
||||
int row = 0; |
|
||||
bool inverse = false; |
|
||||
|
|
||||
// TODO: DoVerticalFilter_C with parameters after stride and after height set to 0
|
|
||||
int startOffset = row * stride; |
|
||||
int lastRow = row + height; |
|
||||
SanityCheck(input, output, width, height, height, stride, row); |
|
||||
inputOffset += startOffset; |
|
||||
outputOffset += startOffset; |
|
||||
Span<byte> preds; |
|
||||
int predsOffset; |
|
||||
|
|
||||
if (inverse) |
|
||||
{ |
|
||||
preds = output; |
|
||||
predsOffset = outputOffset; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
preds = input; |
|
||||
predsOffset = inputOffset; |
|
||||
} |
|
||||
|
|
||||
if (row == 0) |
|
||||
{ |
|
||||
// Very first top-left pixel is copied.
|
|
||||
output[0] = input[0]; |
|
||||
|
|
||||
// Rest of top scan-line is left-predicted:
|
|
||||
PredictLine( |
|
||||
input, |
|
||||
inputOffset + 1, |
|
||||
preds, |
|
||||
predsOffset, |
|
||||
output, |
|
||||
outputOffset + 1, |
|
||||
width - 1, |
|
||||
inverse); |
|
||||
row = 1; |
|
||||
inputOffset += stride; |
|
||||
outputOffset += stride; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
predsOffset -= stride; |
|
||||
} |
|
||||
|
|
||||
// Filter line-by-line.
|
|
||||
while (row < lastRow) |
|
||||
{ |
|
||||
PredictLine( |
|
||||
input, |
|
||||
inputOffset, |
|
||||
preds, |
|
||||
predsOffset, |
|
||||
output, |
|
||||
outputOffset, |
|
||||
width, |
|
||||
inverse); |
|
||||
row++; |
|
||||
predsOffset += stride; |
|
||||
inputOffset += stride; |
|
||||
outputOffset += stride; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,31 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.WebP |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Enum for the different alpha filter types.
|
||||
|
/// </summary>
|
||||
|
internal enum WebPAlphaFilterType |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// No filtering.
|
||||
|
/// </summary>
|
||||
|
None = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Horizontal filter.
|
||||
|
/// </summary>
|
||||
|
Horizontal = 1, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Vertical filter.
|
||||
|
/// </summary>
|
||||
|
Vertical = 2, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gradient filter.
|
||||
|
/// </summary>
|
||||
|
Gradient = 3, |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue