Browse Source

Add additional comments

pull/1552/head
Brian Popow 6 years ago
parent
commit
b2b9a28085
  1. 11
      src/ImageSharp/Formats/WebP/ColorCache.cs
  2. 3
      src/ImageSharp/Formats/WebP/HuffmanCode.cs
  3. 2
      src/ImageSharp/Formats/WebP/HuffmanUtils.cs
  4. 66
      src/ImageSharp/Formats/WebP/LosslessUtils.cs
  5. 17
      src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
  6. 13
      src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

11
src/ImageSharp/Formats/WebP/ColorCache.cs

@ -3,6 +3,9 @@
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
/// A small hash-addressed array to store recently used colors, to be able to recall them with shorter codes.
/// </summary>
internal class ColorCache
{
private const uint KHashMul = 0x1e35a7bdu;
@ -22,6 +25,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public int HashBits { get; private set; }
/// <summary>
/// Initializes a new color cache.
/// </summary>
/// <param name="hashBits">The hashBits determine the size of cache. It will be 1 left shifted by hashBits.</param>
public void Init(int hashBits)
{
int hashSize = 1 << hashBits;
@ -30,6 +37,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.HashShift = 32 - hashBits;
}
/// <summary>
/// Inserts a new color into the cache.
/// </summary>
/// <param name="argb">The color to insert.</param>
public void Insert(uint argb)
{
int key = this.HashPix(argb, this.HashShift);

3
src/ImageSharp/Formats/WebP/HuffmanCode.cs

@ -5,6 +5,9 @@ using System.Diagnostics;
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
/// A classic way to do entropy coding where a smaller number of bits are used for more frequent codes.
/// </summary>
[DebuggerDisplay("BitsUsed: {BitsUsed}, Value: {Value}")]
internal class HuffmanCode
{

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

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Guard.NotNull(codeLengths, nameof(codeLengths));
Guard.MustBeGreaterThan(codeLengthsSize, 0, nameof(codeLengthsSize));
// sorted[code_lengths_size] is a pre-allocated array for sorting symbols by code length.
// sorted[codeLengthsSize] is a pre-allocated array for sorting symbols by code length.
var sorted = new int[codeLengthsSize];
int totalSize = 1 << rootBits; // total size root table + 2nd level table.
int len; // current code length.

66
src/ImageSharp/Formats/WebP/LosslessUtils.cs

@ -30,6 +30,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
/// <summary>
/// If there are not many unique pixel values, it may be more efficient to create a color index array and replace the pixel values by the array's indices.
/// This will reverse the color index transform.
/// </summary>
/// <param name="transform">The transform data contains color table size and the entries in the color table.</param>
/// <param name="pixelData">The pixel data to apply the reverse transform on.</param>
public static void ColorIndexInverseTransform(Vp8LTransform transform, Span<uint> pixelData)
{
int bitsPerPixel = 8 >> transform.Bits;
@ -80,6 +86,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
/// <summary>
/// The goal of the color transform is to de-correlate the R, G and B values of each pixel.
/// Color transform keeps the green (G) value as it is, transforms red (R) based on green and transforms blue (B) based on green and then based on red.
/// </summary>
/// <param name="transform">The transform data.</param>
/// <param name="pixelData">The pixel data to apply the inverse transform on.</param>
public static void ColorSpaceInverseTransform(Vp8LTransform transform, Span<uint> pixelData)
{
int width = transform.XSize;
@ -124,6 +136,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
/// <summary>
/// Reverses the color space transform.
/// </summary>
/// <param name="m">The color transform element.</param>
/// <param name="pixelData">The pixel data to apply the inverse transform on.</param>
/// <param name="start">The start index of reverse transform.</param>
/// <param name="numPixels">The number of pixels to apply the transform.</param>
public static void TransformColorInverse(Vp8LMultipliers m, Span<uint> pixelData, int start, int numPixels)
{
int end = start + numPixels;
@ -144,24 +163,14 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void ExpandColorMap(int numColors, Span<uint> transformData, Span<uint> newColorMap)
{
newColorMap[0] = transformData[0];
Span<byte> data = MemoryMarshal.Cast<uint, byte>(transformData);
Span<byte> newData = MemoryMarshal.Cast<uint, byte>(newColorMap);
int i;
for (i = 4; i < 4 * numColors; ++i)
{
// Equivalent to AddPixelEq(), on a byte-basis.
newData[i] = (byte)((data[i] + newData[i - 4]) & 0xff);
}
for (; i < 4 * newColorMap.Length; ++i)
{
newData[i] = 0; // black tail.
}
}
/// <summary>
/// The predictor transform can be used to reduce entropy by exploiting the fact that neighboring pixels are often correlated.
/// In the predictor transform, the current pixel value is predicted from the pixels already decoded (in scan-line order) and only the residual value (actual - predicted) is encoded.
/// The prediction mode determines the type of prediction to use. We divide the image into squares and all the pixels in a square use same prediction mode.
/// </summary>
/// <param name="transform">The transform data.</param>
/// <param name="pixelData">The pixel data to apply the inverse transform.</param>
/// <param name="output">The resulting pixel data with the reversed transformation data.</param>
public static void PredictorInverseTransform(Vp8LTransform transform, Span<uint> pixelData, Span<uint> output)
{
int processedPixels = 0;
@ -198,6 +207,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
xEnd = width;
}
// There are 14 different prediction modes.
// In each prediction mode, the current pixel value is predicted from one or more neighboring pixels whose values are already known.
int startIdx = processedPixels + x;
int numberOfPixels = xEnd - x;
switch (predictorMode)
@ -602,9 +613,26 @@ namespace SixLabors.ImageSharp.Formats.WebP
return (idx >> 8) & 0xff;
}
public static void ExpandColorMap(int numColors, Span<uint> transformData, Span<uint> newColorMap)
{
newColorMap[0] = transformData[0];
Span<byte> data = MemoryMarshal.Cast<uint, byte>(transformData);
Span<byte> newData = MemoryMarshal.Cast<uint, byte>(newColorMap);
int i;
for (i = 4; i < 4 * numColors; ++i)
{
// Equivalent to AddPixelEq(), on a byte-basis.
newData[i] = (byte)((data[i] + newData[i - 4]) & 0xff);
}
for (; i < 4 * newColorMap.Length; ++i)
{
newData[i] = 0; // black tail.
}
}
private static int ColorTransformDelta(sbyte colorPred, sbyte color)
{
int delta = ((sbyte)colorPred * color) >> 5;
return ((int)colorPred * color) >> 5;
}

17
src/ImageSharp/Formats/WebP/WebPDecoderCore.cs

@ -162,13 +162,20 @@ namespace SixLabors.ImageSharp.Formats.WebP
return new WebPImageInfo();
}
/// <summary>
/// Reads an the extended webp file header. An extended file header consists of:
/// - A 'VP8X' chunk with information about features used in the file.
/// - An optional 'ICCP' chunk with color profile.
/// - An optional 'ANIM' chunk with animation control data.
/// After the image header, image data will follow. After that optional image metadata chunks (EXIF and XMP) can follow.
/// </summary>
/// <returns>Information about this webp image.</returns>
private WebPImageInfo ReadVp8XHeader()
{
uint chunkSize = this.ReadChunkSize();
// This byte contains information about the image features used.
// The first two bit should and the last bit should be 0.
// TODO: should an exception be thrown if its not the case, or just ignore it?
// The first byte contains information about the image features used.
// The first two bit of it are reserved and should be 0. TODO: should an exception be thrown if its not the case, or just ignore it?
byte imageFeatures = (byte)this.currentStream.ReadByte();
// If bit 3 is set, a ICC Profile Chunk should be present.
@ -349,7 +356,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
/// <summary>
/// Parses optional metadata chunks.
/// Parses optional metadata chunks. There SHOULD be at most one chunk of each type ('EXIF' and 'XMP ').
/// If there are more such chunks, readers MAY ignore all except the first one.
/// Also, a file may possibly contain both 'EXIF' and 'XMP ' chunks.
/// </summary>
/// <param name="features">The webp features.</param>
private void ParseOptionalChunks(WebPFeatures features)

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

@ -108,6 +108,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
transform.Data?.Dispose();
}
decoder.Metadata?.HuffmanImage?.Dispose();
}
@ -644,12 +645,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
case Vp8LTransformType.PredictorTransform:
case Vp8LTransformType.CrossColorTransform:
{
// The first 3 bits of prediction data define the block width and height in number of bits.
transform.Bits = (int)this.bitReader.ReadBits(3) + 2;
IMemoryOwner<uint> transformData = this.DecodeImageStream(
decoder,
LosslessUtils.SubSampleSize(transform.XSize, transform.Bits),
LosslessUtils.SubSampleSize(transform.YSize, transform.Bits),
false);
int blockWidth = LosslessUtils.SubSampleSize(transform.XSize, transform.Bits);
int blockHeight = LosslessUtils.SubSampleSize(transform.YSize, transform.Bits);
IMemoryOwner<uint> transformData = this.DecodeImageStream(decoder, blockWidth, blockHeight, false);
transform.Data = transformData;
break;
}
@ -659,7 +659,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
/// <summary>
/// Reverses the transformations, if any are present.
/// A WebP lossless image can go through four different types of transformation before being entropy encoded.
/// This will reverses the transformations, if any are present.
/// </summary>
/// <param name="decoder">The decoder holding the transformation infos.</param>
/// <param name="pixelData">The pixel data to apply the transformation.</param>

Loading…
Cancel
Save