Browse Source

Add ColorIndexInverseTransform

pull/1552/head
Brian Popow 6 years ago
parent
commit
c9b3f1fa25
  1. 114
      src/ImageSharp/Formats/WebP/LosslessUtils.cs
  2. 9
      src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

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

@ -1,3 +1,6 @@
using System;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
@ -22,6 +25,57 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
public static void ColorIndexInverseTransform(Vp8LTransform transform, uint[] pixelData)
{
int bitsPerPixel = 8 >> transform.Bits;
int width = transform.XSize;
int height = transform.YSize;
uint[] colorMap = transform.Data;
int decodedPixels = 0;
if (bitsPerPixel < 8)
{
int pixelsPerByte = 1 << transform.Bits;
int countMask = pixelsPerByte - 1;
int bitMask = (1 << bitsPerPixel) - 1;
// TODO: use memoryAllocator here
var decodedPixelData = new uint[width * height];
int pixelDataPos = 0;
for (int y = 0; y < height; ++y)
{
uint packedPixels = 0;
for (int x = 0; x < width; ++x)
{
// We need to load fresh 'packed_pixels' once every
// 'pixelsPerByte' increments of x. Fortunately, pixelsPerByte
// is a power of 2, so can just use a mask for that, instead of
// decrementing a counter.
if ((x & countMask) is 0)
{
packedPixels = GetARGBIndex(pixelData[pixelDataPos++]);
}
decodedPixelData[decodedPixels++] = colorMap[packedPixels & bitMask];
packedPixels >>= bitsPerPixel;
}
}
decodedPixelData.AsSpan().CopyTo(pixelData);
return;
}
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
uint colorMapIndex = GetARGBIndex(pixelData[decodedPixels]);
pixelData[decodedPixels] = colorMap[colorMapIndex];
decodedPixels++;
}
}
}
public static void ColorSpaceInverseTransform(Vp8LTransform transform, uint[] pixelData)
{
int width = transform.XSize;
@ -78,11 +132,36 @@ namespace SixLabors.ImageSharp.Formats.WebP
newBlue += ColorTransformDelta(m.GreenToBlue, (sbyte)green);
newBlue += ColorTransformDelta(m.RedToBlue, (sbyte)newRed);
newBlue &= 0xff;
var pixelValue = (uint)((argb & 0xff00ff00u) | (newRed << 16) | newBlue);
// uint pixelValue = (uint)((argb & 0xff00ff00u) | (newRed << 16) | newBlue);
pixelData[i] = (uint)((argb & 0xff00ff00u) | (newRed << 16) | newBlue);
}
}
public static uint[] ExpandColorMap(int numColors, Vp8LTransform transform, uint[] transformData)
{
int finalNumColors = 1 << (8 >> transform.Bits);
// TODO: use memoryAllocator here
var newColorMap = new uint[finalNumColors];
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 * finalNumColors; ++i)
{
newData[i] = 0; // black tail.
}
return newColorMap;
}
/// <summary>
/// Computes sampled size of 'size' when sampling using 'sampling bits'.
/// </summary>
@ -91,6 +170,39 @@ namespace SixLabors.ImageSharp.Formats.WebP
return (size + (1 << samplingBits) - 1) >> samplingBits;
}
/// <summary>
/// Sum of each component, mod 256.
/// </summary>
private static uint AddPixels(uint a, uint b)
{
uint alphaAndGreen = (a & 0xff00ff00u) + (b & 0xff00ff00u);
uint redAndBlue = (a & 0x00ff00ffu) + (b & 0x00ff00ffu);
return (alphaAndGreen & 0xff00ff00u) | (redAndBlue & 0x00ff00ffu);
}
/// <summary>
/// Difference of each component, mod 256.
/// </summary>
private static uint SubPixels(uint a, uint b)
{
uint alphaAndGreen = 0x00ff00ffu + (a & 0xff00ff00u) - (b & 0xff00ff00u);
uint redAndBlue = 0xff00ff00u + (a & 0x00ff00ffu) - (b & 0x00ff00ffu);
return (alphaAndGreen & 0xff00ff00u) | (redAndBlue & 0x00ff00ffu);
}
private static void PredictorAdd1(uint[] pixelData, int numPixels)
{
/*for (int i = 0; i < num_pixels; ++i)
{
pixelData[i] = VP8LAddPixels(in[i], left);
}*/
}
private static uint GetARGBIndex(uint idx)
{
return (idx >> 8) & 0xff;
}
private static int ColorTransformDelta(sbyte colorPred, sbyte color)
{
return ((int)colorPred * color) >> 5;

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

@ -603,7 +603,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
: 3;
transform.XSize = LosslessUtils.SubSampleSize(transform.XSize, bits);
transform.Bits = bits;
transform.Data = this.DecodeImageStream(decoder, (int)numColors, 1, false);
uint[] colorMap = this.DecodeImageStream(decoder, (int)numColors, 1, false);
transform.Data = LosslessUtils.ExpandColorMap((int)numColors, transform, colorMap);
break;
case Vp8LTransformType.PredictorTransform:
@ -635,12 +636,18 @@ namespace SixLabors.ImageSharp.Formats.WebP
Vp8LTransformType transformType = transforms[i].TransformType;
switch (transformType)
{
case Vp8LTransformType.PredictorTransform:
// LosslessUtils.PredictorInverseTransform(transforms[i], pixelData);
break;
case Vp8LTransformType.SubtractGreen:
LosslessUtils.AddGreenToBlueAndRed(pixelData);
break;
case Vp8LTransformType.CrossColorTransform:
LosslessUtils.ColorSpaceInverseTransform(transforms[i], pixelData);
break;
case Vp8LTransformType.ColorIndexingTransform:
LosslessUtils.ColorIndexInverseTransform(transforms[i], pixelData);
break;
}
}
}

Loading…
Cancel
Save