Browse Source

Alpha now uses FastBitmap

Former-commit-id: 7c2d70dc94c67c84b48084480a776f3b2d4ec6fe
Former-commit-id: 71a7b03cfb9c3e4754e1ffb4a12bd9d7e5b1eb8a
af/merge-core
James South 11 years ago
parent
commit
860dde8cee
  1. 3
      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

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

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fa4aeb79b1c2c20697d8feb5997d2756a7d007a4f530d03148301a0e51beded2
size 155

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

@ -101,28 +101,28 @@ namespace ImageProcessor.Imaging.Formats
if (this.IsIndexed)
{
// 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);
clone.SetResolution(image.HorizontalResolution, image.VerticalResolution);
Bitmap clone = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb);
clone.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (Graphics graphics = Graphics.FromImage(clone))
{
graphics.Clear(Color.Transparent);
graphics.DrawImage(image, new Rectangle(0, 0, clone.Width, clone.Height));
}
using (Graphics graphics = Graphics.FromImage(clone))
{
graphics.Clear(Color.Transparent);
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);
//}
//else
//{
// image = new WuQuantizer().QuantizeImage((Bitmap)image);
//}
// image = new OctreeQuantizer(255, 8).Quantize(image);
}
else
{
image = new WuQuantizer().QuantizeImage((Bitmap)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.Drawing;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using ImageProcessor.Imaging.Colors;
/// <summary>
/// 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.");
}
Rectangle bounds = rectangle.HasValue ? rectangle.Value : new Rectangle(0, 0, source.Width, source.Height);
ColorMatrix colorMatrix = new ColorMatrix();
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);
float factor = (float)percentage / 100;
int width = source.Width;
int height = source.Height;
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);
using (ImageAttributes imageAttributes = new ImageAttributes())
{
imageAttributes.SetColorMatrix(colorMatrix);
graphics.DrawImage(source, bounds, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel, imageAttributes);
}
// Loop through the pixels.
Parallel.For(
0,
height,
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 alpha;
return (Bitmap)source;
}
/// <summary>

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

@ -1,8 +1,7 @@
//using System.Runtime.CompilerServices;

namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
{
struct ColorMoment
internal struct ColorMoment
{
public long Alpha;
public long Red;
@ -44,7 +43,6 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
return c1;
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(Pixel p)
{
byte pAlpha = p.Alpha;
@ -59,7 +57,6 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
Moment += pAlpha * pAlpha + pRed * pRed + pGreen * pGreen + pBlue * pBlue;
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddFast(ref ColorMoment c2)
{
Alpha += c2.Alpha;
@ -77,12 +74,12 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer
public long WeightedDistance()
{
return Amplitude() / Weight;
return this.Amplitude() / this.Weight;
}
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;
}
}

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

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

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

Loading…
Cancel
Save