diff --git a/src/ImageProcessorCore/Formats/Gif/GifEncoder.cs b/src/ImageProcessorCore/Formats/Gif/GifEncoder.cs
index 5fb3e4b8e9..4dd43f30f7 100644
--- a/src/ImageProcessorCore/Formats/Gif/GifEncoder.cs
+++ b/src/ImageProcessorCore/Formats/Gif/GifEncoder.cs
@@ -23,10 +23,15 @@ namespace ImageProcessorCore.Formats
/// For gifs the value ranges from 1 to 256.
public int Quality { get; set; }
+ ///
+ /// Gets or sets the transparency threshold.
+ ///
+ public byte Threshold { get; set; } = 128;
+
///
/// The quantizer for reducing the color count.
///
- public IQuantizer Quantizer { get; set; } = new OctreeQuantizer();
+ public IQuantizer Quantizer { get; set; }
///
public string Extension => "gif";
@@ -51,6 +56,11 @@ namespace ImageProcessorCore.Formats
Image image = (Image)imageBase;
+ if (this.Quantizer == null)
+ {
+ this.Quantizer = new OctreeQuantizer { Threshold = this.Threshold };
+ }
+
// Write the header.
// File Header signature and version.
this.WriteString(stream, GifConstants.FileType);
diff --git a/src/ImageProcessorCore/Quantizers/IQuantizer.cs b/src/ImageProcessorCore/Quantizers/IQuantizer.cs
index 68f7554dab..3196ebf9f1 100644
--- a/src/ImageProcessorCore/Quantizers/IQuantizer.cs
+++ b/src/ImageProcessorCore/Quantizers/IQuantizer.cs
@@ -10,6 +10,11 @@ namespace ImageProcessorCore.Quantizers
///
public interface IQuantizer
{
+ ///
+ /// Gets or sets the transparency threshold.
+ ///
+ byte Threshold { get; set; }
+
///
/// Quantize an image and return the resulting output pixels.
///
diff --git a/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs b/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs
index 1ef4cd541c..c0c900145b 100644
--- a/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs
+++ b/src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs
@@ -36,11 +36,6 @@ namespace ImageProcessorCore.Quantizers
{
}
- ///
- /// Gets or sets the transparency threshold.
- ///
- public byte Threshold { get; set; } = 128;
-
///
public override QuantizedImage Quantize(ImageBase image, int maxColors)
{
diff --git a/src/ImageProcessorCore/Quantizers/Octree/Quantizer.cs b/src/ImageProcessorCore/Quantizers/Octree/Quantizer.cs
index 3c66cc944c..0db212da57 100644
--- a/src/ImageProcessorCore/Quantizers/Octree/Quantizer.cs
+++ b/src/ImageProcessorCore/Quantizers/Octree/Quantizer.cs
@@ -7,6 +7,7 @@ namespace ImageProcessorCore.Quantizers
{
using System;
using System.Collections.Generic;
+ using System.Threading.Tasks;
///
/// Encapsulates methods to calculate the color palette of an image.
@@ -39,6 +40,9 @@ namespace ImageProcessorCore.Quantizers
///
public int TransparentIndex { get; protected set; } = -1;
+ ///
+ public byte Threshold { get; set; }
+
///
public virtual QuantizedImage Quantize(ImageBase image, int maxColors)
{
@@ -95,35 +99,17 @@ namespace ImageProcessorCore.Quantizers
/// The height in pixels of the image
protected virtual void SecondPass(ImageBase source, byte[] output, int width, int height)
{
- int i = 0;
-
- // Convert the first pixel, so that I have values going into the loop.
- // Implicit cast here from Color.
- Bgra32 previousPixel = source[0, 0];
- byte pixelValue = this.QuantizePixel(previousPixel);
-
- output[0] = pixelValue;
-
- for (int y = 0; y < height; y++)
- {
- for (int x = 0; x < width; x++)
- {
- Bgra32 sourcePixel = source[x, y];
-
- // Check if this is the same as the last pixel. If so use that value
- // rather than calculating it again. This is an inexpensive optimization.
- if (sourcePixel != previousPixel)
+ Parallel.For(
+ 0,
+ source.Height,
+ y =>
{
- // Quantize the pixel
- pixelValue = this.QuantizePixel(sourcePixel);
-
- // And setup the previous pointer
- previousPixel = sourcePixel;
- }
-
- output[i++] = pixelValue;
- }
- }
+ for (int x = 0; x < source.Width; x++)
+ {
+ Bgra32 sourcePixel = source[x, y];
+ output[(y * source.Width) + x] = this.QuantizePixel(sourcePixel);
+ }
+ });
}
///
diff --git a/src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs b/src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs
index 74f192834d..47f77a8777 100644
--- a/src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs
+++ b/src/ImageProcessorCore/Quantizers/Palette/PaletteQuantizer.cs
@@ -35,9 +35,16 @@ namespace ImageProcessorCore.Quantizers
public PaletteQuantizer(Color[] palette = null)
: base(true)
{
- this.colors = palette == null
- ? ColorConstants.WebSafeColors.Select(c => (Bgra32)c).ToArray()
- : palette.Select(c => (Bgra32)c).ToArray();
+ if (palette == null)
+ {
+ List safe = ColorConstants.WebSafeColors.Select(c => (Bgra32)c).ToList();
+ safe.Insert(0, Bgra32.Empty);
+ this.colors = safe.ToArray();
+ }
+ else
+ {
+ this.colors = palette.Select(c => (Bgra32)c).ToArray();
+ }
}
///
@@ -61,8 +68,8 @@ namespace ImageProcessorCore.Quantizers
else
{
// Not found - loop through the palette and find the nearest match.
- // Firstly check the alpha value - if 0, lookup the transparent color
- if (pixel.A == 0)
+ // Firstly check the alpha value - if less than the threshold, lookup the transparent color
+ if (!(pixel.A > this.Threshold))
{
// Transparent. Lookup the first color with an alpha value of 0
for (int index = 0; index < this.colors.Length; index++)
@@ -91,7 +98,7 @@ namespace ImageProcessorCore.Quantizers
int redDistance = paletteColor.R - red;
int greenDistance = paletteColor.G - green;
int blueDistance = paletteColor.B - blue;
-
+
int distance = (redDistance * redDistance) +
(greenDistance * greenDistance) +
(blueDistance * blueDistance);
@@ -111,7 +118,7 @@ namespace ImageProcessorCore.Quantizers
}
// Now I have the color, pop it into the cache for next time
- this.colorMap.Add(colorHash, colorIndex);
+ this.colorMap[colorHash] = colorIndex;
}
return colorIndex;
diff --git a/src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs b/src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs
index 9bb4e5f842..55e0bdcc99 100644
--- a/src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs
+++ b/src/ImageProcessorCore/Quantizers/Wu/WuQuantizer.cs
@@ -7,6 +7,7 @@ namespace ImageProcessorCore.Quantizers
{
using System;
using System.Collections.Generic;
+ using System.Threading.Tasks;
///
/// An implementation of Wu's color quantizer with alpha channel.
@@ -110,6 +111,9 @@ namespace ImageProcessorCore.Quantizers
this.tag = new byte[TableLength];
}
+ ///
+ public byte Threshold { get; set; }
+
///
public QuantizedImage Quantize(ImageBase image, int maxColors)
{
@@ -730,7 +734,7 @@ namespace ImageProcessorCore.Quantizers
byte b = (byte)(Volume(cube[k], this.vmb) / weight);
byte a = (byte)(Volume(cube[k], this.vma) / weight);
- var color = new Bgra32(b, g, r, a);
+ Bgra32 color = new Bgra32(b, g, r, a);
if (color == Bgra32.Empty)
{
@@ -746,22 +750,29 @@ namespace ImageProcessorCore.Quantizers
}
}
- // TODO: Optimize here.
- int i = 0;
- for (int y = 0; y < image.Height; y++)
- {
- for (int x = 0; x < image.Width; x++)
- {
- Bgra32 color = image[x, y];
- int a = color.A >> (8 - IndexAlphaBits);
- int r = color.R >> (8 - IndexBits);
- int g = color.G >> (8 - IndexBits);
- int b = color.B >> (8 - IndexBits);
-
- int ind = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
- pixels[i++] = this.tag[ind];
- }
- }
+ Parallel.For(
+ 0,
+ image.Height,
+ y =>
+ {
+ for (int x = 0; x < image.Width; x++)
+ {
+ Bgra32 color = image[x, y];
+ int a = color.A >> (8 - IndexAlphaBits);
+ int r = color.R >> (8 - IndexBits);
+ int g = color.G >> (8 - IndexBits);
+ int b = color.B >> (8 - IndexBits);
+
+ if (transparentIndex > -1 && color.A <= this.Threshold)
+ {
+ pixels[(y * image.Width) + x] = (byte)transparentIndex;
+ continue;
+ }
+
+ int ind = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
+ pixels[(y * image.Width) + x] = this.tag[ind];
+ }
+ });
return new QuantizedImage(image.Width, image.Height, pallette.ToArray(), pixels, transparentIndex);
}
diff --git a/tests/ImageProcessorCore.Tests/Processors/Formats/EncoderDecoderTests.cs b/tests/ImageProcessorCore.Tests/Processors/Formats/EncoderDecoderTests.cs
index c5eea6ba05..33df554423 100644
--- a/tests/ImageProcessorCore.Tests/Processors/Formats/EncoderDecoderTests.cs
+++ b/tests/ImageProcessorCore.Tests/Processors/Formats/EncoderDecoderTests.cs
@@ -62,7 +62,7 @@
using (FileStream output = File.OpenWrite($"TestOutput/Quantize/{Path.GetFileName(file)}"))
{
- quantizedImage.ToImage().Save(output);
+ quantizedImage.ToImage().Save(output, image.CurrentImageFormat);
}
}
}