Browse Source

Alpha now uses FastBitmap

Former-commit-id: 7c2d70dc94c67c84b48084480a776f3b2d4ec6fe
Former-commit-id: 71a7b03cfb9c3e4754e1ffb4a12bd9d7e5b1eb8a
pull/17/head
James South 12 years ago
parent
commit
ced73281fb
  1. BIN
      src/ImageProcessor.Playground/images/input/001.png
  2. 34
      src/ImageProcessor/Imaging/Formats/PngFormat.cs
  3. 42
      src/ImageProcessor/Imaging/Helpers/Adjustments.cs
  4. 11
      src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ColorMoment.cs
  5. 7
      src/ImageProcessor/Imaging/Quantizers/WuQuantizer/WuQuantizer.cs
  6. 48
      src/ImageProcessor/Imaging/Quantizers/WuQuantizer/WuQuantizerBase.cs

BIN
src/ImageProcessor.Playground/images/input/001.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

34
src/ImageProcessor/Imaging/Formats/PngFormat.cs

@ -101,28 +101,28 @@ namespace ImageProcessor.Imaging.Formats
if (this.IsIndexed) if (this.IsIndexed)
{ {
// The Wu Quantizer expects a 32bbp image. // The Wu Quantizer expects a 32bbp image.
//if (Image.GetPixelFormatSize(image.PixelFormat) != 32) if (Image.GetPixelFormatSize(image.PixelFormat) != 32)
//{ {
Bitmap clone = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb); Bitmap clone = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb);
clone.SetResolution(image.HorizontalResolution, image.VerticalResolution); clone.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (Graphics graphics = Graphics.FromImage(clone)) using (Graphics graphics = Graphics.FromImage(clone))
{ {
graphics.Clear(Color.Transparent); graphics.Clear(Color.Transparent);
graphics.DrawImage(image, new Rectangle(0, 0, clone.Width, clone.Height)); graphics.DrawImage(image, new Rectangle(0, 0, clone.Width, clone.Height));
} }
image.Dispose(); image.Dispose();
image = new WuQuantizer().QuantizeImage(clone); image = new WuQuantizer().QuantizeImage(clone);
// image = new OctreeQuantizer(255, 8).Quantize(image); // image = new OctreeQuantizer(255, 8).Quantize(image);
//} }
//else else
//{ {
// image = new WuQuantizer().QuantizeImage((Bitmap)image); image = new WuQuantizer().QuantizeImage((Bitmap)image);
//} }
} }
return base.Save(path, image); return base.Save(path, image);

42
src/ImageProcessor/Imaging/Helpers/Adjustments.cs

@ -13,6 +13,9 @@ namespace ImageProcessor.Imaging.Helpers
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Threading.Tasks;
using ImageProcessor.Imaging.Colors;
/// <summary> /// <summary>
/// Provides reusable adjustment methods to apply to images. /// Provides reusable adjustment methods to apply to images.
@ -43,27 +46,30 @@ namespace ImageProcessor.Imaging.Helpers
throw new ArgumentOutOfRangeException("percentage", "Percentage should be between 0 and 100."); throw new ArgumentOutOfRangeException("percentage", "Percentage should be between 0 and 100.");
} }
Rectangle bounds = rectangle.HasValue ? rectangle.Value : new Rectangle(0, 0, source.Width, source.Height); float factor = (float)percentage / 100;
int width = source.Width;
ColorMatrix colorMatrix = new ColorMatrix(); int height = source.Height;
colorMatrix.Matrix00 = colorMatrix.Matrix11 = colorMatrix.Matrix22 = colorMatrix.Matrix44 = 1;
colorMatrix.Matrix33 = (float)percentage / 100;
Bitmap alpha = new Bitmap(source.Width, source.Height);
alpha.SetResolution(source.HorizontalResolution, source.VerticalResolution);
using (Graphics graphics = Graphics.FromImage(alpha)) // Traditional examples using a color matrix alter the rgb values also.
using (FastBitmap bitmap = new FastBitmap(source))
{ {
graphics.Clear(Color.Transparent); // Loop through the pixels.
using (ImageAttributes imageAttributes = new ImageAttributes()) Parallel.For(
{ 0,
imageAttributes.SetColorMatrix(colorMatrix); height,
graphics.DrawImage(source, bounds, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel, imageAttributes); y =>
} {
for (int x = 0; x < width; x++)
{
// ReSharper disable AccessToDisposedClosure
Color color = bitmap.GetPixel(x, y);
bitmap.SetPixel(x, y, Color.FromArgb(Convert.ToInt32(color.A * factor), color.R, color.G, color.B));
// ReSharper restore AccessToDisposedClosure
}
});
} }
source.Dispose(); return (Bitmap)source;
return alpha;
} }
/// <summary> /// <summary>

11
src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ColorMoment.cs

@ -1,8 +1,7 @@
//using System.Runtime.CompilerServices; 
namespace ImageProcessor.Imaging.Quantizers.WuQuantizer namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
{ {
struct ColorMoment internal struct ColorMoment
{ {
public long Alpha; public long Alpha;
public long Red; public long Red;
@ -44,7 +43,6 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
return c1; return c1;
} }
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(Pixel p) public void Add(Pixel p)
{ {
byte pAlpha = p.Alpha; byte pAlpha = p.Alpha;
@ -59,7 +57,6 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
Moment += pAlpha * pAlpha + pRed * pRed + pGreen * pGreen + pBlue * pBlue; Moment += pAlpha * pAlpha + pRed * pRed + pGreen * pGreen + pBlue * pBlue;
} }
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddFast(ref ColorMoment c2) public void AddFast(ref ColorMoment c2)
{ {
Alpha += c2.Alpha; Alpha += c2.Alpha;
@ -77,12 +74,12 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
public long WeightedDistance() public long WeightedDistance()
{ {
return Amplitude() / Weight; return this.Amplitude() / this.Weight;
} }
public float Variance() public float Variance()
{ {
var result = Moment - (float)Amplitude() / Weight; float result = this.Moment - ((float)this.Amplitude() / this.Weight);
return float.IsNaN(result) ? 0.0f : result; return float.IsNaN(result) ? 0.0f : result;
} }
} }

7
src/ImageProcessor/Imaging/Quantizers/WuQuantizer/WuQuantizer.cs

@ -8,8 +8,8 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
{ {
private static IEnumerable<byte[]> IndexedPixels(ImageBuffer image, Pixel[] lookups, int alphaThreshold, PaletteColorHistory[] paletteHistogram) private static IEnumerable<byte[]> IndexedPixels(ImageBuffer image, Pixel[] lookups, int alphaThreshold, PaletteColorHistory[] paletteHistogram)
{ {
var lineIndexes = new byte[image.Image.Width]; byte[] lineIndexes = new byte[image.Image.Width];
var lookup = new PaletteLookup(lookups); PaletteLookup lookup = new PaletteLookup(lookups);
foreach (var pixelLine in image.PixelLines) foreach (var pixelLine in image.PixelLines)
{ {
for (int pixelIndex = 0; pixelIndex < pixelLine.Length; pixelIndex++) for (int pixelIndex = 0; pixelIndex < pixelLine.Length; pixelIndex++)
@ -21,8 +21,10 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
bestMatch = lookup.GetPaletteIndex(pixel); bestMatch = lookup.GetPaletteIndex(pixel);
paletteHistogram[bestMatch].AddPixel(pixel); paletteHistogram[bestMatch].AddPixel(pixel);
} }
lineIndexes[pixelIndex] = bestMatch; lineIndexes[pixelIndex] = bestMatch;
} }
yield return lineIndexes; yield return lineIndexes;
} }
} }
@ -43,6 +45,7 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
{ {
palette.Entries[paletteColorIndex] = paletteHistogram[paletteColorIndex].ToNormalizedColor(); palette.Entries[paletteColorIndex] = paletteHistogram[paletteColorIndex].ToNormalizedColor();
} }
return palette; return palette;
} }
} }

48
src/ImageProcessor/Imaging/Quantizers/WuQuantizer/WuQuantizerBase.cs

@ -17,7 +17,7 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
internal void Clear() internal void Clear()
{ {
Array.Clear(Moments, 0, SideSize*SideSize*SideSize*SideSize); Array.Clear(Moments, 0, SideSize * SideSize * SideSize * SideSize);
} }
} }
@ -46,32 +46,35 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
var buffer = new ImageBuffer(image); var buffer = new ImageBuffer(image);
if (histogram == null) if (histogram == null)
{
histogram = new Histogram(); histogram = new Histogram();
}
else else
{
histogram.Clear(); histogram.Clear();
}
BuildHistogram(histogram, buffer, alphaThreshold, alphaFader); BuildHistogram(histogram, buffer, alphaThreshold, alphaFader);
CalculateMoments(histogram.Moments); CalculateMoments(histogram.Moments);
var cubes = SplitData(ref maxColors, histogram.Moments); var cubes = SplitData(ref maxColors, histogram.Moments);
var lookups = BuildLookups(cubes, histogram.Moments); var lookups = BuildLookups(cubes, histogram.Moments);
return GetQuantizedImage(buffer, maxColors, lookups, alphaThreshold); return this.GetQuantizedImage(buffer, maxColors, lookups, alphaThreshold);
} }
private static void BuildHistogram(Histogram histogram, ImageBuffer sourceImage, int alphaThreshold, int alphaFader) private static void BuildHistogram(Histogram histogram, ImageBuffer sourceImage, int alphaThreshold, int alphaFader)
{ {
var moments = histogram.Moments; ColorMoment[,,,] moments = histogram.Moments;
foreach(var pixelLine in sourceImage.PixelLines) foreach (Pixel[] pixelLine in sourceImage.PixelLines)
{ {
for (int pixelIndex = 0; pixelIndex < pixelLine.Length; pixelIndex++) foreach (Pixel pixel in pixelLine)
{ {
Pixel pixel = pixelLine[pixelIndex];
byte pixelAlpha = pixel.Alpha; byte pixelAlpha = pixel.Alpha;
if (pixelAlpha >= alphaThreshold) if (pixelAlpha >= alphaThreshold)
{ {
if (pixelAlpha < 255) if (pixelAlpha < 255)
{ {
var alpha = pixel.Alpha + (pixel.Alpha % alphaFader); int alpha = pixel.Alpha + (pixel.Alpha % alphaFader);
pixelAlpha = (byte)(alpha > 255 ? 255 : alpha); pixelAlpha = (byte)(alpha > 255 ? 255 : alpha);
} }
@ -91,17 +94,17 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
private static void CalculateMoments(ColorMoment[, , ,] moments) private static void CalculateMoments(ColorMoment[, , ,] moments)
{ {
var xarea = new ColorMoment[SideSize, SideSize]; ColorMoment[,] xarea = new ColorMoment[SideSize, SideSize];
var area = new ColorMoment[SideSize]; ColorMoment[] area = new ColorMoment[SideSize];
for (var alphaIndex = 1; alphaIndex < SideSize; alphaIndex++) for (int alphaIndex = 1; alphaIndex < SideSize; alphaIndex++)
{ {
for (var redIndex = 1; redIndex < SideSize; redIndex++) for (int redIndex = 1; redIndex < SideSize; redIndex++)
{ {
Array.Clear(area, 0, area.Length); Array.Clear(area, 0, area.Length);
for (var greenIndex = 1; greenIndex < SideSize; greenIndex++) for (int greenIndex = 1; greenIndex < SideSize; greenIndex++)
{ {
var line = new ColorMoment(); ColorMoment line = new ColorMoment();
for (var blueIndex = 1; blueIndex < SideSize; blueIndex++) for (int blueIndex = 1; blueIndex < SideSize; blueIndex++)
{ {
line.AddFast(ref moments[alphaIndex, redIndex, greenIndex, blueIndex]); line.AddFast(ref moments[alphaIndex, redIndex, greenIndex, blueIndex]);
area[blueIndex].AddFast(ref line); area[blueIndex].AddFast(ref line);
@ -220,10 +223,13 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
var result = 0.0f; var result = 0.0f;
byte? cutPoint = null; byte? cutPoint = null;
for (var position = first; position < last; ++position) for (byte position = first; position < last; ++position)
{ {
var half = bottom + Top(cube, direction, position, moments); ColorMoment half = bottom + Top(cube, direction, position, moments);
if (half.Weight == 0) continue; if (half.Weight == 0)
{
continue;
}
var temp = half.WeightedDistance(); var temp = half.WeightedDistance();
@ -275,28 +281,28 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
switch (direction) switch (direction)
{ {
case Alpha: case Alpha:
second.AlphaMinimum = first.AlphaMaximum = (byte) maxAlpha.Position; second.AlphaMinimum = first.AlphaMaximum = (byte)maxAlpha.Position;
second.RedMinimum = first.RedMinimum; second.RedMinimum = first.RedMinimum;
second.GreenMinimum = first.GreenMinimum; second.GreenMinimum = first.GreenMinimum;
second.BlueMinimum = first.BlueMinimum; second.BlueMinimum = first.BlueMinimum;
break; break;
case Red: case Red:
second.RedMinimum = first.RedMaximum = (byte) maxRed.Position; second.RedMinimum = first.RedMaximum = (byte)maxRed.Position;
second.AlphaMinimum = first.AlphaMinimum; second.AlphaMinimum = first.AlphaMinimum;
second.GreenMinimum = first.GreenMinimum; second.GreenMinimum = first.GreenMinimum;
second.BlueMinimum = first.BlueMinimum; second.BlueMinimum = first.BlueMinimum;
break; break;
case Green: case Green:
second.GreenMinimum = first.GreenMaximum = (byte) maxGreen.Position; second.GreenMinimum = first.GreenMaximum = (byte)maxGreen.Position;
second.AlphaMinimum = first.AlphaMinimum; second.AlphaMinimum = first.AlphaMinimum;
second.RedMinimum = first.RedMinimum; second.RedMinimum = first.RedMinimum;
second.BlueMinimum = first.BlueMinimum; second.BlueMinimum = first.BlueMinimum;
break; break;
case Blue: case Blue:
second.BlueMinimum = first.BlueMaximum = (byte) maxBlue.Position; second.BlueMinimum = first.BlueMaximum = (byte)maxBlue.Position;
second.AlphaMinimum = first.AlphaMinimum; second.AlphaMinimum = first.AlphaMinimum;
second.RedMinimum = first.RedMinimum; second.RedMinimum = first.RedMinimum;
second.GreenMinimum = first.GreenMinimum; second.GreenMinimum = first.GreenMinimum;

Loading…
Cancel
Save