Browse Source

Fix cross-format quantization

Png can now store more transparent pixels when indexed and work with all
quantizers.


Former-commit-id: 6a4724535829d2c73024b6b1f0235e94e25ccad1
Former-commit-id: 24e4cfff4583c97caef30369302340a3a75ea57a
Former-commit-id: 56ff119c5a2a2506f06b59a23e5e13ec0c3a4688
pull/1/head
James Jackson-South 10 years ago
parent
commit
354af45815
  1. 42
      src/ImageProcessorCore/Formats/Gif/GifEncoderCore.cs
  2. 8
      src/ImageProcessorCore/Formats/Png/PngEncoder.cs
  3. 16
      src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs
  4. 4
      src/ImageProcessorCore/Quantizers/IQuantizer.cs
  5. 62
      src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs
  6. 10
      src/ImageProcessorCore/Quantizers/Octree/Quantizer.cs
  7. 69
      src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs
  8. 11
      src/ImageProcessorCore/Quantizers/QuantizedImage.cs
  9. 29
      src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs

42
src/ImageProcessorCore/Formats/Gif/GifEncoderCore.cs

@ -55,7 +55,7 @@ namespace ImageProcessorCore.Formats
if (this.Quantizer == null) if (this.Quantizer == null)
{ {
this.Quantizer = new OctreeQuantizer<TColor, TPacked> { Threshold = this.Threshold }; this.Quantizer = new OctreeQuantizer<TColor, TPacked>();
} }
// Do not use IDisposable pattern here as we want to preserve the stream. // Do not use IDisposable pattern here as we want to preserve the stream.
@ -71,14 +71,16 @@ namespace ImageProcessorCore.Formats
// Quantize the image returning a palette. // Quantize the image returning a palette.
QuantizedImage<TColor, TPacked> quantized = ((IQuantizer<TColor, TPacked>)this.Quantizer).Quantize(image, this.Quality); QuantizedImage<TColor, TPacked> quantized = ((IQuantizer<TColor, TPacked>)this.Quantizer).Quantize(image, this.Quality);
int index = GetTransparentIndex(quantized);
// Write the header. // Write the header.
this.WriteHeader(writer); this.WriteHeader(writer);
// Write the LSD. We'll use local color tables for now. // Write the LSD. We'll use local color tables for now.
this.WriteLogicalScreenDescriptor(image, writer, quantized.TransparentIndex); this.WriteLogicalScreenDescriptor(image, writer, index);
// Write the first frame. // Write the first frame.
this.WriteGraphicalControlExtension(image, writer, quantized.TransparentIndex); this.WriteGraphicalControlExtension(image, writer, index);
this.WriteImageDescriptor(image, writer); this.WriteImageDescriptor(image, writer);
this.WriteColorTable(quantized, writer); this.WriteColorTable(quantized, writer);
this.WriteImageData(quantized, writer); this.WriteImageData(quantized, writer);
@ -90,7 +92,8 @@ namespace ImageProcessorCore.Formats
foreach (ImageFrame<TColor, TPacked> frame in image.Frames) foreach (ImageFrame<TColor, TPacked> frame in image.Frames)
{ {
QuantizedImage<TColor, TPacked> quantizedFrame = ((IQuantizer<TColor, TPacked>)this.Quantizer).Quantize(frame, this.Quality); QuantizedImage<TColor, TPacked> quantizedFrame = ((IQuantizer<TColor, TPacked>)this.Quantizer).Quantize(frame, this.Quality);
this.WriteGraphicalControlExtension(frame, writer, quantizedFrame.TransparentIndex);
this.WriteGraphicalControlExtension(frame, writer, GetTransparentIndex(quantizedFrame));
this.WriteImageDescriptor(frame, writer); this.WriteImageDescriptor(frame, writer);
this.WriteColorTable(quantizedFrame, writer); this.WriteColorTable(quantizedFrame, writer);
this.WriteImageData(quantizedFrame, writer); this.WriteImageData(quantizedFrame, writer);
@ -101,6 +104,37 @@ namespace ImageProcessorCore.Formats
writer.Write(GifConstants.EndIntroducer); writer.Write(GifConstants.EndIntroducer);
} }
/// <summary>
/// Returns the index of the most transparent color in the palette.
/// </summary>
/// <param name="quantized">
/// The quantized.
/// </param>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
/// <returns>
/// The <see cref="int"/>.
/// </returns>
private static int GetTransparentIndex<TColor, TPacked>(QuantizedImage<TColor, TPacked> quantized)
where TColor : IPackedVector<TPacked>
where TPacked : struct
{
// Find the lowest alpha value and make it the transparent index.
int index = 255;
float alpha = 1;
for (int i = 0; i < quantized.Palette.Length; i++)
{
float a = quantized.Palette[i].ToVector4().W;
if (a < alpha)
{
alpha = a;
index = i;
}
}
return index;
}
/// <summary> /// <summary>
/// Writes the file header signature and version to the stream. /// Writes the file header signature and version to the stream.
/// </summary> /// </summary>

8
src/ImageProcessorCore/Formats/Png/PngEncoder.cs

@ -32,7 +32,7 @@ namespace ImageProcessorCore.Formats
public string Extension => "png"; public string Extension => "png";
/// <summary> /// <summary>
/// The compression level 1-9. /// Gets or sets the compression level 1-9.
/// <remarks>Defaults to 6.</remarks> /// <remarks>Defaults to 6.</remarks>
/// </summary> /// </summary>
public int CompressionLevel { get; set; } = 6; public int CompressionLevel { get; set; } = 6;
@ -46,14 +46,14 @@ namespace ImageProcessorCore.Formats
public float Gamma { get; set; } = 2.2F; public float Gamma { get; set; } = 2.2F;
/// <summary> /// <summary>
/// The quantizer for reducing the color count. /// Gets or sets quantizer for reducing the color count.
/// </summary> /// </summary>
public IQuantizer Quantizer { get; set; } public IQuantizer Quantizer { get; set; }
/// <summary> /// <summary>
/// Gets or sets the transparency threshold. /// Gets or sets the transparency threshold.
/// </summary> /// </summary>
public byte Threshold { get; set; } = 128; public byte Threshold { get; set; } = 0;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether this instance should write /// Gets or sets a value indicating whether this instance should write
@ -81,7 +81,7 @@ namespace ImageProcessorCore.Formats
CompressionLevel = this.CompressionLevel, CompressionLevel = this.CompressionLevel,
Gamma = this.Gamma, Gamma = this.Gamma,
Quality = this.Quality, Quality = this.Quality,
PngColorType = PngColorType, PngColorType = this.PngColorType,
Quantizer = this.Quantizer, Quantizer = this.Quantizer,
WriteGamma = this.WriteGamma, WriteGamma = this.WriteGamma,
Threshold = this.Threshold Threshold = this.Threshold

16
src/ImageProcessorCore/Formats/Png/PngEncoderCore.cs

@ -8,6 +8,7 @@ namespace ImageProcessorCore.Formats
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Quantizers; using Quantizers;
@ -86,7 +87,7 @@ namespace ImageProcessorCore.Formats
/// <summary> /// <summary>
/// Gets or sets the transparency threshold. /// Gets or sets the transparency threshold.
/// </summary> /// </summary>
public byte Threshold { get; set; } = 128; public byte Threshold { get; set; }
/// <summary> /// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageBase{TColor, TPacked}"/>. /// Encodes the image to the specified stream from the <see cref="ImageBase{TColor, TPacked}"/>.
@ -492,7 +493,7 @@ namespace ImageProcessorCore.Formats
if (this.Quantizer == null) if (this.Quantizer == null)
{ {
this.Quantizer = new WuQuantizer<TColor, TPacked> { Threshold = this.Threshold }; this.Quantizer = new WuQuantizer<TColor, TPacked>();
} }
// Quantize the image returning a palette. This boxing is icky. // Quantize the image returning a palette. This boxing is icky.
@ -501,7 +502,7 @@ namespace ImageProcessorCore.Formats
// Grab the palette and write it to the stream. // Grab the palette and write it to the stream.
TColor[] palette = quantized.Palette; TColor[] palette = quantized.Palette;
int pixelCount = palette.Length; int pixelCount = palette.Length;
List<byte> transparentPixels = new List<byte>();
// Get max colors for bit depth. // Get max colors for bit depth.
int colorTableLength = (int)Math.Pow(2, header.BitDepth) * 3; int colorTableLength = (int)Math.Pow(2, header.BitDepth) * 3;
byte[] colorTable = new byte[colorTableLength]; byte[] colorTable = new byte[colorTableLength];
@ -517,14 +518,19 @@ namespace ImageProcessorCore.Formats
colorTable[offset] = color.R; colorTable[offset] = color.R;
colorTable[offset + 1] = color.G; colorTable[offset + 1] = color.G;
colorTable[offset + 2] = color.B; colorTable[offset + 2] = color.B;
if (color.A <= this.Threshold)
{
transparentPixels.Add((byte)offset);
}
}); });
this.WriteChunk(stream, PngChunkTypes.Palette, colorTable); this.WriteChunk(stream, PngChunkTypes.Palette, colorTable);
// Write the transparency data // Write the transparency data
if (quantized.TransparentIndex > -1) if (transparentPixels.Any())
{ {
this.WriteChunk(stream, PngChunkTypes.PaletteAlpha, new[] { (byte)quantized.TransparentIndex }); this.WriteChunk(stream, PngChunkTypes.PaletteAlpha, transparentPixels.ToArray());
} }
return quantized; return quantized;

4
src/ImageProcessorCore/Quantizers/IQuantizer.cs

@ -30,9 +30,5 @@ namespace ImageProcessorCore.Quantizers
/// </summary> /// </summary>
public interface IQuantizer public interface IQuantizer
{ {
/// <summary>
/// Gets or sets the transparency threshold.
/// </summary>
byte Threshold { get; set; }
} }
} }

62
src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs

@ -7,7 +7,6 @@ namespace ImageProcessorCore.Quantizers
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
/// <summary> /// <summary>
/// Encapsulates methods to calculate the colour palette if an image using an Octree pattern. /// Encapsulates methods to calculate the colour palette if an image using an Octree pattern.
@ -44,7 +43,7 @@ namespace ImageProcessorCore.Quantizers
/// <inheritdoc/> /// <inheritdoc/>
public override QuantizedImage<TColor, TPacked> Quantize(ImageBase<TColor, TPacked> image, int maxColors) public override QuantizedImage<TColor, TPacked> Quantize(ImageBase<TColor, TPacked> image, int maxColors)
{ {
this.colors = maxColors.Clamp(1, 255); this.colors = maxColors.Clamp(1, 256);
if (this.octree == null) if (this.octree == null)
{ {
@ -80,16 +79,7 @@ namespace ImageProcessorCore.Quantizers
/// </returns> /// </returns>
protected override byte QuantizePixel(TColor pixel) protected override byte QuantizePixel(TColor pixel)
{ {
// The color at [maxColors] is set to transparent return (byte)this.octree.GetPaletteIndex(pixel);
byte paletteIndex = (byte)this.colors;
// Get the palette index if it's transparency meets criterea.
if (new Color(pixel.ToVector4()).A > this.Threshold)
{
paletteIndex = (byte)this.octree.GetPaletteIndex(pixel);
}
return paletteIndex;
} }
/// <summary> /// <summary>
@ -100,17 +90,18 @@ namespace ImageProcessorCore.Quantizers
/// </returns> /// </returns>
protected override List<TColor> GetPalette() protected override List<TColor> GetPalette()
{ {
return this.octree.Palletize(Math.Max(this.colors, 1));
// First off convert the Octree to maxColors colors // First off convert the Octree to maxColors colors
List<TColor> palette = this.octree.Palletize(Math.Max(this.colors, 1)); //List<TColor> palette = this.octree.Palletize(Math.Max(this.colors, 1));
int diff = this.colors - palette.Count; //int diff = this.colors - palette.Count;
if (diff > 0) //if (diff > 0)
{ //{
palette.AddRange(Enumerable.Repeat(default(TColor), diff)); // palette.AddRange(Enumerable.Repeat(default(TColor), diff));
} //}
this.TransparentIndex = this.colors;
return palette; //return palette;
} }
/// <summary> /// <summary>
@ -134,7 +125,7 @@ namespace ImageProcessorCore.Quantizers
/// <summary> /// <summary>
/// Mask used when getting the appropriate pixels for a given node /// Mask used when getting the appropriate pixels for a given node
/// </summary> /// </summary>
private static readonly int[] Mask = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; private static readonly int[] Mask = { 0x100, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
/// <summary> /// <summary>
/// The root of the Octree /// The root of the Octree
@ -196,6 +187,7 @@ namespace ImageProcessorCore.Quantizers
public void AddColor(TColor pixel) public void AddColor(TColor pixel)
{ {
TPacked packed = pixel.PackedValue; TPacked packed = pixel.PackedValue;
// Check if this request is for the same color as the last // Check if this request is for the same color as the last
if (this.previousColor.Equals(packed)) if (this.previousColor.Equals(packed))
{ {
@ -324,6 +316,11 @@ namespace ImageProcessorCore.Quantizers
/// </summary> /// </summary>
private int blue; private int blue;
/// <summary>
/// Alpha component
/// </summary>
private int alpha;
/// <summary> /// <summary>
/// The index of this node in the palette /// The index of this node in the palette
/// </summary> /// </summary>
@ -346,7 +343,7 @@ namespace ImageProcessorCore.Quantizers
// Construct the new node // Construct the new node
this.leaf = level == colorBits; this.leaf = level == colorBits;
this.red = this.green = this.blue = 0; this.red = this.green = this.blue = this.alpha = 0;
this.pixelCount = 0; this.pixelCount = 0;
// If a leaf, increment the leaf count // If a leaf, increment the leaf count
@ -392,9 +389,10 @@ namespace ImageProcessorCore.Quantizers
// Go to the next level down in the tree // Go to the next level down in the tree
int shift = 7 - level; int shift = 7 - level;
Color color = new Color(pixel.ToVector4()); Color color = new Color(pixel.ToVector4());
int index = ((color.B & Mask[level]) >> (shift - 2)) | int index = ((color.A & Mask[0]) >> (shift - 3)) |
((color.G & Mask[level]) >> (shift - 1)) | ((color.B & Mask[level + 1]) >> (shift - 2)) |
((color.R & Mask[level]) >> shift); ((color.G & Mask[level + 1]) >> (shift - 1)) |
((color.R & Mask[level + 1]) >> shift);
OctreeNode child = this.children[index]; OctreeNode child = this.children[index];
@ -416,7 +414,7 @@ namespace ImageProcessorCore.Quantizers
/// <returns>The number of leaves removed</returns> /// <returns>The number of leaves removed</returns>
public int Reduce() public int Reduce()
{ {
this.red = this.green = this.blue = 0; this.red = this.green = this.blue = this.alpha = 0;
int childNodes = 0; int childNodes = 0;
// Loop through all children and add their information to this node // Loop through all children and add their information to this node
@ -427,6 +425,7 @@ namespace ImageProcessorCore.Quantizers
this.red += this.children[index].red; this.red += this.children[index].red;
this.green += this.children[index].green; this.green += this.children[index].green;
this.blue += this.children[index].blue; this.blue += this.children[index].blue;
this.alpha += this.children[index].alpha;
this.pixelCount += this.children[index].pixelCount; this.pixelCount += this.children[index].pixelCount;
++childNodes; ++childNodes;
this.children[index] = null; this.children[index] = null;
@ -455,10 +454,11 @@ namespace ImageProcessorCore.Quantizers
byte r = (this.red / this.pixelCount).ToByte(); byte r = (this.red / this.pixelCount).ToByte();
byte g = (this.green / this.pixelCount).ToByte(); byte g = (this.green / this.pixelCount).ToByte();
byte b = (this.blue / this.pixelCount).ToByte(); byte b = (this.blue / this.pixelCount).ToByte();
byte a = (this.alpha / this.pixelCount).ToByte();
// And set the color of the palette entry // And set the color of the palette entry
TColor pixel = default(TColor); TColor pixel = default(TColor);
pixel.PackFromVector4(new Color(r, g, b).ToVector4()); pixel.PackFromVector4(new Color(r, g, b, a).ToVector4());
palette.Add(pixel); palette.Add(pixel);
} }
else else
@ -490,9 +490,10 @@ namespace ImageProcessorCore.Quantizers
{ {
int shift = 7 - level; int shift = 7 - level;
Color color = new Color(pixel.ToVector4()); Color color = new Color(pixel.ToVector4());
int pixelIndex = ((color.B & Mask[level]) >> (shift - 2)) | int pixelIndex = ((color.A & Mask[0]) >> (shift - 3)) |
((color.G & Mask[level]) >> (shift - 1)) | ((color.B & Mask[level + 1]) >> (shift - 2)) |
((color.R & Mask[level]) >> shift); ((color.G & Mask[level + 1]) >> (shift - 1)) |
((color.R & Mask[level + 1]) >> shift);
if (this.children[pixelIndex] != null) if (this.children[pixelIndex] != null)
{ {
@ -520,6 +521,7 @@ namespace ImageProcessorCore.Quantizers
this.red += color.R; this.red += color.R;
this.green += color.G; this.green += color.G;
this.blue += color.B; this.blue += color.B;
this.alpha += color.A;
} }
} }
} }

10
src/ImageProcessorCore/Quantizers/Octree/Quantizer.cs

@ -38,14 +38,6 @@ namespace ImageProcessorCore.Quantizers
this.singlePass = singlePass; this.singlePass = singlePass;
} }
/// <summary>
/// Gets or sets the transparency index.
/// </summary>
public int TransparentIndex { get; protected set; } = -1;
/// <inheritdoc/>
public byte Threshold { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public virtual QuantizedImage<TColor, TPacked> Quantize(ImageBase<TColor, TPacked> image, int maxColors) public virtual QuantizedImage<TColor, TPacked> Quantize(ImageBase<TColor, TPacked> image, int maxColors)
{ {
@ -73,7 +65,7 @@ namespace ImageProcessorCore.Quantizers
this.SecondPass(pixels, quantizedPixels, width, height); this.SecondPass(pixels, quantizedPixels, width, height);
} }
return new QuantizedImage<TColor, TPacked>(width, height, palette.ToArray(), quantizedPixels, this.TransparentIndex); return new QuantizedImage<TColor, TPacked>(width, height, palette.ToArray(), quantizedPixels);
} }
/// <summary> /// <summary>

69
src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs

@ -80,51 +80,36 @@ namespace ImageProcessorCore.Quantizers
else else
{ {
// Not found - loop through the palette and find the nearest match. // Not found - loop through the palette and find the nearest match.
// Firstly check the alpha value - if less than the threshold, lookup the transparent color Color color = new Color(pixel.ToVector4());
Color color =new Color(pixel.ToVector4());
if (!(color.A > this.Threshold)) int leastDistance = int.MaxValue;
{ int red = color.R;
// Transparent. Lookup the first color with an alpha value of 0 int green = color.G;
for (int index = 0; index < this.colors.Length; index++) int blue = color.B;
{ int alpha = color.A;
if (new Color(this.colors[index].ToVector4()).A == 0)
{ for (int index = 0; index < this.colors.Length; index++)
colorIndex = (byte)index;
this.TransparentIndex = colorIndex;
break;
}
}
}
else
{ {
// Not transparent... Color paletteColor = new Color(this.colors[index].ToVector4());
int leastDistance = int.MaxValue; int redDistance = paletteColor.R - red;
int red = color.R; int greenDistance = paletteColor.G - green;
int green = color.G; int blueDistance = paletteColor.B - blue;
int blue = color.B; int alphaDistance = paletteColor.A - alpha;
// Loop through the entire palette, looking for the closest color match
for (int index = 0; index < this.colors.Length; index++)
{
Color paletteColor = new Color(this.colors[index].ToVector4());
int redDistance = paletteColor.R - red;
int greenDistance = paletteColor.G - green;
int blueDistance = paletteColor.B - blue;
int distance = (redDistance * redDistance) + int distance = (redDistance * redDistance) +
(greenDistance * greenDistance) + (greenDistance * greenDistance) +
(blueDistance * blueDistance); (blueDistance * blueDistance) +
(alphaDistance * alphaDistance);
if (distance < leastDistance) if (distance < leastDistance)
{
colorIndex = (byte)index;
leastDistance = distance;
// And if it's an exact match, exit the loop
if (distance == 0)
{ {
colorIndex = (byte)index; break;
leastDistance = distance;
// And if it's an exact match, exit the loop
if (distance == 0)
{
break;
}
} }
} }
} }
@ -142,4 +127,4 @@ namespace ImageProcessorCore.Quantizers
return this.colors.ToList(); return this.colors.ToList();
} }
} }
} }

11
src/ImageProcessorCore/Quantizers/QuantizedImage.cs

@ -24,8 +24,7 @@ namespace ImageProcessorCore.Quantizers
/// <param name="height">The image height.</param> /// <param name="height">The image height.</param>
/// <param name="palette">The color palette.</param> /// <param name="palette">The color palette.</param>
/// <param name="pixels">The quantized pixels.</param> /// <param name="pixels">The quantized pixels.</param>
/// <param name="transparentIndex">The transparency index.</param> public QuantizedImage(int width, int height, TColor[] palette, byte[] pixels)
public QuantizedImage(int width, int height, TColor[] palette, byte[] pixels, int transparentIndex = -1)
{ {
Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.MustBeGreaterThan(height, 0, nameof(height));
@ -42,7 +41,6 @@ namespace ImageProcessorCore.Quantizers
this.Height = height; this.Height = height;
this.Palette = palette; this.Palette = palette;
this.Pixels = pixels; this.Pixels = pixels;
this.TransparentIndex = transparentIndex;
} }
/// <summary> /// <summary>
@ -65,11 +63,6 @@ namespace ImageProcessorCore.Quantizers
/// </summary> /// </summary>
public byte[] Pixels { get; } public byte[] Pixels { get; }
/// <summary>
/// Gets the transparent index
/// </summary>
public int TransparentIndex { get; }
/// <summary> /// <summary>
/// Converts this quantized image to a normal image. /// Converts this quantized image to a normal image.
/// </summary> /// </summary>
@ -98,4 +91,4 @@ namespace ImageProcessorCore.Quantizers
return image; return image;
} }
} }
} }

29
src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs

@ -117,9 +117,6 @@ namespace ImageProcessorCore.Quantizers
this.tag = new byte[TableLength]; this.tag = new byte[TableLength];
} }
/// <inheritdoc/>
public byte Threshold { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public QuantizedImage<TColor, TPacked> Quantize(ImageBase<TColor, TPacked> image, int maxColors) public QuantizedImage<TColor, TPacked> Quantize(ImageBase<TColor, TPacked> image, int maxColors)
{ {
@ -334,7 +331,7 @@ namespace ImageProcessorCore.Quantizers
for (int x = 0; x < pixels.Width; x++) for (int x = 0; x < pixels.Width; x++)
{ {
// Colors are expected in r->g->b->a format // Colors are expected in r->g->b->a format
Color color = new Color(pixels[x, y].ToVector4()); Color color = new Color(pixels[x, y].ToVector4());
byte r = color.R; byte r = color.R;
byte g = color.G; byte g = color.G;
@ -729,7 +726,6 @@ namespace ImageProcessorCore.Quantizers
{ {
List<TColor> pallette = new List<TColor>(); List<TColor> pallette = new List<TColor>();
byte[] pixels = new byte[imagePixels.Width * imagePixels.Height]; byte[] pixels = new byte[imagePixels.Width * imagePixels.Height];
int transparentIndex = -1;
int width = imagePixels.Width; int width = imagePixels.Width;
int height = imagePixels.Height; int height = imagePixels.Height;
@ -741,25 +737,18 @@ namespace ImageProcessorCore.Quantizers
if (Math.Abs(weight) > Epsilon) if (Math.Abs(weight) > Epsilon)
{ {
byte r = (byte)(Volume(cube[k], this.vmr) / weight); float r = (float)(Volume(cube[k], this.vmr) / weight);
byte g = (byte)(Volume(cube[k], this.vmg) / weight); float g = (float)(Volume(cube[k], this.vmg) / weight);
byte b = (byte)(Volume(cube[k], this.vmb) / weight); float b = (float)(Volume(cube[k], this.vmb) / weight);
byte a = (byte)(Volume(cube[k], this.vma) / weight); float a = (float)(Volume(cube[k], this.vma) / weight);
TColor color = default(TColor); TColor color = default(TColor);
color.PackFromVector4(new Vector4(r, g, b, a) / 255F); color.PackFromVector4(new Vector4(r, g, b, a) / 255F);
if (color.Equals(default(TColor)))
{
transparentIndex = k;
}
pallette.Add(color); pallette.Add(color);
} }
else else
{ {
pallette.Add(default(TColor)); pallette.Add(default(TColor));
transparentIndex = k;
} }
} }
@ -778,18 +767,12 @@ namespace ImageProcessorCore.Quantizers
int b = color.B >> (8 - IndexBits); int b = color.B >> (8 - IndexBits);
int a = color.A >> (8 - IndexAlphaBits); int a = color.A >> (8 - IndexAlphaBits);
if (transparentIndex > -1 && color.A <= this.Threshold)
{
pixels[(y * width) + x] = (byte)transparentIndex;
continue;
}
int ind = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); int ind = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
pixels[(y * width) + x] = this.tag[ind]; pixels[(y * width) + x] = this.tag[ind];
} }
}); });
return new QuantizedImage<TColor, TPacked>(width, height, pallette.ToArray(), pixels, transparentIndex); return new QuantizedImage<TColor, TPacked>(width, height, pallette.ToArray(), pixels);
} }
} }
} }
Loading…
Cancel
Save