mirror of https://github.com/SixLabors/ImageSharp
6 changed files with 495 additions and 103 deletions
@ -0,0 +1,101 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Derives AV1 palette color-index ordering and entropy contexts from preceding spatial indices.
|
||||
|
/// </summary>
|
||||
|
internal static class Av1PaletteColorMap |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Derives the palette color order, current color-order index, and entropy context for one map position.
|
||||
|
/// </summary>
|
||||
|
/// <param name="colorIndexMap">The partially or completely populated color-index map.</param>
|
||||
|
/// <param name="row">The current map row.</param>
|
||||
|
/// <param name="column">The current map column.</param>
|
||||
|
/// <param name="paletteSize">The number of colors in the palette.</param>
|
||||
|
/// <param name="colorIndex">The current palette index, or a negative value while decoding.</param>
|
||||
|
/// <param name="colorOrder">The destination color order for the current context.</param>
|
||||
|
/// <param name="colorOrderIndex">The current index in <paramref name="colorOrder" />, or a negative value while decoding.</param>
|
||||
|
/// <returns>The color-index entropy context in the range from zero through four.</returns>
|
||||
|
public static int GetContext( |
||||
|
Buffer2DRegion<byte> colorIndexMap, |
||||
|
int row, |
||||
|
int column, |
||||
|
int paletteSize, |
||||
|
int colorIndex, |
||||
|
Span<byte> colorOrder, |
||||
|
out int colorOrderIndex) |
||||
|
{ |
||||
|
Span<int> scores = stackalloc int[Av1Constants.PaletteMaxSize]; |
||||
|
scores.Clear(); |
||||
|
ReadOnlySpan<byte> currentRow = colorIndexMap.DangerousGetRowSpan(row); |
||||
|
if (column > 0) |
||||
|
{ |
||||
|
scores[currentRow[column - 1]] += 2; |
||||
|
} |
||||
|
|
||||
|
if (row > 0) |
||||
|
{ |
||||
|
ReadOnlySpan<byte> aboveRow = colorIndexMap.DangerousGetRowSpan(row - 1); |
||||
|
if (column > 0) |
||||
|
{ |
||||
|
scores[aboveRow[column - 1]]++; |
||||
|
} |
||||
|
|
||||
|
scores[aboveRow[column]] += 2; |
||||
|
} |
||||
|
|
||||
|
Span<int> inverseColorOrder = stackalloc int[Av1Constants.PaletteMaxSize]; |
||||
|
for (int i = 0; i < Av1Constants.PaletteMaxSize; i++) |
||||
|
{ |
||||
|
colorOrder[i] = (byte)i; |
||||
|
inverseColorOrder[i] = i; |
||||
|
} |
||||
|
|
||||
|
// Stable descending score order keeps lower palette indices ahead when neighboring scores tie.
|
||||
|
for (int i = 0; i < 3; i++) |
||||
|
{ |
||||
|
int maximumScore = scores[i]; |
||||
|
int maximumIndex = i; |
||||
|
for (int j = i + 1; j < paletteSize; j++) |
||||
|
{ |
||||
|
if (scores[j] > maximumScore) |
||||
|
{ |
||||
|
maximumScore = scores[j]; |
||||
|
maximumIndex = j; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (maximumIndex != i) |
||||
|
{ |
||||
|
byte maximumColor = colorOrder[maximumIndex]; |
||||
|
for (int j = maximumIndex; j > i; j--) |
||||
|
{ |
||||
|
scores[j] = scores[j - 1]; |
||||
|
colorOrder[j] = colorOrder[j - 1]; |
||||
|
inverseColorOrder[colorOrder[j]] = j; |
||||
|
} |
||||
|
|
||||
|
scores[i] = maximumScore; |
||||
|
colorOrder[i] = maximumColor; |
||||
|
inverseColorOrder[maximumColor] = i; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
colorOrderIndex = colorIndex < 0 ? -1 : inverseColorOrder[colorIndex]; |
||||
|
int contextHash = scores[0] + (2 * scores[1]) + (2 * scores[2]); |
||||
|
return contextHash switch |
||||
|
{ |
||||
|
2 => 0, |
||||
|
5 => 4, |
||||
|
6 => 3, |
||||
|
7 => 2, |
||||
|
8 => 1, |
||||
|
_ => -1 |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue