public void Dispose() { buf.Dispose(); buf = null; bmp.Dispose(); bmp = null; }
public void Init() { bmp = new Bitmap(6,6); for(int i=0; i<6; i++) { int col = 255-i*51; bmp.SetPixel(0,i, Color.FromArgb(col,0,0)); bmp.SetPixel(1,i, Color.FromArgb(col,col,0)); bmp.SetPixel(2,i, Color.FromArgb(0,col,0)); bmp.SetPixel(3,i, Color.FromArgb(0,col,col)); bmp.SetPixel(4,i, Color.FromArgb(0,0,col)); bmp.SetPixel(5,i, Color.FromArgb(col,0,col)); } buf = new BitmapBuffer(bmp); bmpRect = new Bitmap(6,6); for(int i=0; i<6; i++) { int col = 255-i*51; bmpRect.SetPixel(0,i, Color.FromArgb(col,0,0)); bmpRect.SetPixel(1,i, Color.FromArgb(col,col,0)); bmpRect.SetPixel(2,i, Color.FromArgb(0,col,0)); bmpRect.SetPixel(3,i, Color.FromArgb(0,col,col)); bmpRect.SetPixel(4,i, Color.FromArgb(0,0,col)); bmpRect.SetPixel(5,i, Color.FromArgb(col,0,col)); } bufRect = new BitmapBuffer(bmpRect,new Rectangle(2,2,2,2)); }
public override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { magnificationFactor = GetFieldValueAsInt(FieldType.MAGNIFICATION_FACTOR); applyRect = ImageHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); bbbSrc = new BitmapBuffer(applyBitmap, applyRect); try { bbbSrc.Lock(); base.Apply(graphics, applyBitmap, applyRect, renderMode); } finally { bbbSrc.Dispose(); bbbSrc = null; } }
public override bool ProcessCapture(ISurface surface, ICaptureDetails captureDetails) { LOG.DebugFormat("Changing surface to grayscale!"); using (BitmapBuffer bbb = new BitmapBuffer(surface.Image as Bitmap, false)) { bbb.Lock(); for(int y=0;y<bbb.Height; y++) { for(int x=0;x<bbb.Width; x++) { Color color = bbb.GetColorAt(x, y); int luma = (int)((0.3*color.R) + (0.59*color.G) + (0.11*color.B)); color = Color.FromArgb(luma, luma, luma); bbb.SetColorAt(x, y, color); } } } return true; }
public static void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, int pixelSize) { if(pixelSize <= 1 || rect.Width == 0 || rect.Height == 0) { // Nothing to do return; } if(rect.Width < pixelSize) pixelSize = rect.Width; if(rect.Height < pixelSize) pixelSize = rect.Height; using (BitmapBuffer bbbDest = new BitmapBuffer(applyBitmap, rect)) { bbbDest.Lock(); using(BitmapBuffer bbbSrc = new BitmapBuffer(applyBitmap, rect)) { bbbSrc.Lock(); List<Color> colors = new List<Color>(); int halbPixelSize = pixelSize/2; for(int y=-halbPixelSize;y<bbbSrc.Height+halbPixelSize; y=y+pixelSize) { for(int x=-halbPixelSize;x<=bbbSrc.Width+halbPixelSize; x=x+pixelSize) { colors.Clear(); for(int yy=y;yy<y+pixelSize;yy++) { if (yy >=0 && yy < bbbSrc.Height) { for(int xx=x;xx<x+pixelSize;xx++) { colors.Add(bbbSrc.GetColorAt(xx,yy)); } } } Color currentAvgColor = Colors.Mix(colors); for(int yy=y;yy<=y+pixelSize;yy++) { if (yy >=0 && yy < bbbSrc.Height) { for(int xx=x;xx<=x+pixelSize;xx++) { bbbDest.SetColorAt(xx, yy, currentAvgColor); } } } } } } bbbDest.DrawTo(graphics, rect.Location); } }
public virtual void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { applyRect = IntersectRectangle(applyBitmap.Size, rect); if (applyRect.Width == 0 || applyRect.Height == 0) { // nothing to do return; } bbb = new BitmapBuffer(applyBitmap, applyRect); try { bbb.Lock(); for(int y=0;y<bbb.Height; y++) { for(int x=0;x<bbb.Width; x++) { if(parent.Contains(applyRect.Left+x, applyRect.Top+y) ^ Invert) { IteratePixel(x, y); } } } } finally { bbb.DrawTo(graphics, applyRect.Location); bbb.Dispose(); bbb = null; } }
private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint) { Rectangle cropRectangle = Rectangle.Empty; Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X, colorPoint.Y); Point min = new Point(int.MaxValue, int.MaxValue); Point max = new Point(int.MinValue, int.MinValue); if (conf.AutoCropDifference > 0) { for (int y = 0; y < buffer.Height; y++) { for (int x = 0; x < buffer.Width; x++) { Color currentColor = buffer.GetColorAt(x, y); int diffR = Math.Abs(currentColor.R - referenceColor.R); int diffG = Math.Abs(currentColor.G - referenceColor.G); int diffB = Math.Abs(currentColor.B - referenceColor.B); if (((diffR + diffG + diffB) / 3) > conf.AutoCropDifference) { if (x < min.X) { min.X = x; } if (y < min.Y) { min.Y = y; } if (x > max.X) { max.X = x; } if (y > max.Y) { max.Y = y; } } } } } else { for (int y = 0; y < buffer.Height; y++) { for (int x = 0; x < buffer.Width; x++) { Color currentColor = buffer.GetColorAtWithoutAlpha(x, y); if (referenceColor.Equals(currentColor)) { if (x < min.X) { min.X = x; } if (y < min.Y) { min.Y = y; } if (x > max.X) { max.X = x; } if (y > max.Y) { max.Y = y; } } } } } if (!(Point.Empty.Equals(min) && max.Equals(new Point(buffer.Width - 1, buffer.Height - 1)))) { if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) { cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); } } return(cropRectangle); }
/// <summary> /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 /// </summary> /// <param name="image"></param> /// <returns>Rectangle</returns> public static Rectangle FindAutoCropRectangle(Image image, int cropDifference) { Rectangle cropRectangle = Rectangle.Empty; using (BitmapBuffer buffer = new BitmapBuffer((Bitmap)image, false)) { buffer.Lock(); Rectangle currentRectangle = Rectangle.Empty; List<Point> checkPoints = new List<Point>(); // Top Left checkPoints.Add(new Point(0, 0)); // Bottom Left checkPoints.Add(new Point(0, image.Height-1)); // Top Right checkPoints.Add(new Point(image.Width-1, 0)); // Bottom Right checkPoints.Add( new Point(image.Width-1, image.Height-1)); // find biggest area foreach(Point checkPoint in checkPoints) { currentRectangle = FindAutoCropRectangle(buffer, checkPoint, cropDifference); if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) { cropRectangle = currentRectangle; } } } return cropRectangle; }
private void SetColorAt(BitmapBuffer bbb, int x, int y, int[] colors) { if(parent.Contains(applyRect.Left+x, applyRect.Top+y) ^ Invert) { bbb.SetColorArrayAt(x, y, colors); } }
/// <summary> /// Create a new bitmap with the sourceBitmap blurred /// </summary> /// <param name="sourceBitmap">Source to blur</param> /// <param name="applyRect">Area to blur</param> /// <param name="useExportQuality">Use best quality</param> /// <param name="blurRadius">Radius of the blur</param> /// <param name="previewQuality">Quality, use 1d for normal anything less skipps calculations</param> /// <param name="invert">true if the blur needs to occur outside of the area</param> /// <param name="parentBounds">Rectangle limiting the area when using invert</param> public static unsafe Bitmap CreateBlur(Bitmap sourceBitmap, Rectangle applyRect, bool useExportQuality, int blurRadius, double previewQuality, bool invert, Rectangle parentBounds) { if (applyRect.Height <= 0 || applyRect.Width <= 0) { return null; } // do nothing when nothing can be done! if (blurRadius < 1) { return null; } byte[] nullColor = new byte[] { 255, 255, 255, 255 }; if (sourceBitmap.PixelFormat == PixelFormat.Format32bppArgb) { nullColor = new byte[] { 0, 0, 0, 0 }; } byte[] settingColor = new byte[4]; byte[] readingColor = new byte[4]; using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect, true)) { bbbDest.Lock(); using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect, false)) { bbbSrc.Lock(); Random rand = new Random(); unchecked { int r = blurRadius; int[] w = CreateGaussianBlurRow(r); int wlen = w.Length; long* waSums = stackalloc long[wlen]; long* wcSums = stackalloc long[wlen]; long* aSums = stackalloc long[wlen]; long* rSums = stackalloc long[wlen]; long* gSums = stackalloc long[wlen]; long* bSums = stackalloc long[wlen]; for (int y = 0; y < applyRect.Height; ++y) { long waSum = 0; long wcSum = 0; long aSum = 0; long rSum = 0; long gSum = 0; long bSum = 0; for (int wx = 0; wx < wlen; ++wx) { int srcX = wx - r; waSums[wx] = 0; wcSums[wx] = 0; aSums[wx] = 0; rSums[wx] = 0; gSums[wx] = 0; bSums[wx] = 0; if (srcX >= 0 && srcX < bbbDest.Width) { for (int wy = 0; wy < wlen; ++wy) { int srcY = y + wy - r; if (srcY >= 0 && srcY < bbbDest.Height) { bbbSrc.GetColorIn(srcX, srcY, readingColor); int wp = w[wy]; waSums[wx] += wp; wp *= readingColor[0] + (readingColor[0] >> 7); wcSums[wx] += wp; wp >>= 8; aSums[wx] += wp * readingColor[0]; rSums[wx] += wp * readingColor[1]; gSums[wx] += wp * readingColor[2]; bSums[wx] += wp * readingColor[3]; } } int wwx = w[wx]; waSum += wwx * waSums[wx]; wcSum += wwx * wcSums[wx]; aSum += wwx * aSums[wx]; rSum += wwx * rSums[wx]; gSum += wwx * gSums[wx]; bSum += wwx * bSums[wx]; } } wcSum >>= 8; if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) { if (waSum == 0 || wcSum == 0) { bbbDest.SetUncheckedColorArrayAt(0, y, nullColor); } else { settingColor[0] = (byte)(aSum / waSum); settingColor[1] = (byte)(rSum / wcSum); settingColor[2] = (byte)(gSum / wcSum); settingColor[3] = (byte)(bSum / wcSum); bbbDest.SetUncheckedColorArrayAt(0, y, settingColor); } } for (int x = 1; x < applyRect.Width; ++x) { for (int i = 0; i < wlen - 1; ++i) { waSums[i] = waSums[i + 1]; wcSums[i] = wcSums[i + 1]; aSums[i] = aSums[i + 1]; rSums[i] = rSums[i + 1]; gSums[i] = gSums[i + 1]; bSums[i] = bSums[i + 1]; } waSum = 0; wcSum = 0; aSum = 0; rSum = 0; gSum = 0; bSum = 0; int wx; for (wx = 0; wx < wlen - 1; ++wx) { long wwx = (long)w[wx]; waSum += wwx * waSums[wx]; wcSum += wwx * wcSums[wx]; aSum += wwx * aSums[wx]; rSum += wwx * rSums[wx]; gSum += wwx * gSums[wx]; bSum += wwx * bSums[wx]; } wx = wlen - 1; waSums[wx] = 0; wcSums[wx] = 0; aSums[wx] = 0; rSums[wx] = 0; gSums[wx] = 0; bSums[wx] = 0; int srcX = x + wx - r; if (srcX >= 0 && srcX < applyRect.Width) { for (int wy = 0; wy < wlen; ++wy) { int srcY = y + wy - r; // only when in EDIT mode, ignore some pixels depending on preview quality if ((useExportQuality || rand.NextDouble() < previewQuality) && srcY >= 0 && srcY < applyRect.Height) { int wp = w[wy]; waSums[wx] += wp; bbbSrc.GetColorIn(srcX, srcY, readingColor); wp *= readingColor[0] + (readingColor[0] >> 7); wcSums[wx] += wp; wp >>= 8; aSums[wx] += wp * readingColor[0]; rSums[wx] += wp * readingColor[1]; gSums[wx] += wp * readingColor[2]; bSums[wx] += wp * readingColor[3]; } } int wr = w[wx]; waSum += wr * waSums[wx]; wcSum += wr * wcSums[wx]; aSum += wr * aSums[wx]; rSum += wr * rSums[wx]; gSum += wr * gSums[wx]; bSum += wr * bSums[wx]; } wcSum >>= 8; if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) { if (waSum == 0 || wcSum == 0) { bbbDest.SetUncheckedColorArrayAt(x, y, nullColor); } else { settingColor[0] = (byte)(aSum / waSum); settingColor[1] = (byte)(rSum / wcSum); settingColor[2] = (byte)(gSum / wcSum); settingColor[3] = (byte)(bSum / wcSum); bbbDest.SetUncheckedColorArrayAt(x, y, settingColor); } } } } } } bbbDest.Unlock(); return bbbDest.Bitmap; } }
/// <summary> /// Return negative of Bitmap /// </summary> /// <param name="sourceBitmap">Bitmap to create a negative off</param> /// <returns>Negative bitmap</returns> public static Bitmap CreateNegative(Bitmap sourceBitmap) { using (BitmapBuffer bb = new BitmapBuffer(sourceBitmap, true)) { bb.Lock(); for (int y = 0; y < bb.Height; y++) { for (int x = 0; x < bb.Width; x++) { Color color = bb.GetColorAt(x, y); Color invertedColor = Color.FromArgb(color.A, color.R ^ 255, color.G ^ 255, color.B ^ 255); bb.SetColorAt(x, y, invertedColor); } } bb.Unlock(); return bb.Bitmap; } }
void DrawImageForPrint(object sender, PrintPageEventArgs e) { PrintOptionsDialog pod = printOptionsDialog; ContentAlignment alignment = pod.AllowPrintCenter ? ContentAlignment.MiddleCenter : ContentAlignment.TopLeft; if (conf.OutputPrintInverted) { // Invert Bitmap BitmapBuffer bb = new BitmapBuffer((Bitmap)image, false); bb.Lock(); for(int y=0;y<bb.Height; y++) { for(int x=0;x<bb.Width; x++) { Color color = bb.GetColorAt(x, y); Color invertedColor = Color.FromArgb(color.A, color.R ^ 255, color.G ^ 255, color.B ^ 255); bb.SetColorAt(x, y, invertedColor); } } bb.Dispose(); } RectangleF pageRect = e.PageSettings.PrintableArea; GraphicsUnit gu = GraphicsUnit.Pixel; RectangleF imageRect = image.GetBounds(ref gu); // rotate the image if it fits the page better if(pod.AllowPrintRotate) { if((pageRect.Width > pageRect.Height && imageRect.Width < imageRect.Height) || (pageRect.Width < pageRect.Height && imageRect.Width > imageRect.Height)) { image.RotateFlip(RotateFlipType.Rotate90FlipNone); imageRect = image.GetBounds(ref gu); if(alignment.Equals(ContentAlignment.TopLeft)) alignment = ContentAlignment.TopRight; } } RectangleF printRect = new RectangleF(0,0,imageRect.Width, imageRect.Height);; // scale the image to fit the page better if(pod.AllowPrintEnlarge || pod.AllowPrintShrink) { SizeF resizedRect = ScaleHelper.GetScaledSize(imageRect.Size,pageRect.Size,false); if((pod.AllowPrintShrink && resizedRect.Width < printRect.Width) || pod.AllowPrintEnlarge && resizedRect.Width > printRect.Width) { printRect.Size = resizedRect; } } // prepare timestamp float dateStringWidth = 0; float dateStringHeight = 0; if (conf.OutputPrintTimestamp) { Font f = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular); string dateString = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString(); dateStringWidth = e.Graphics.MeasureString(dateString, f).Width; dateStringHeight = e.Graphics.MeasureString(dateString, f).Height; e.Graphics.DrawString(dateString, f, Brushes.Black, pageRect.Width / 2 - (dateStringWidth / 2), pageRect.Height - dateStringHeight); } // align the image printRect = ScaleHelper.GetAlignedRectangle(printRect, new RectangleF(0, 0, pageRect.Width, pageRect.Height - dateStringHeight * 2), alignment); e.Graphics.DrawImage(image,printRect,imageRect,GraphicsUnit.Pixel); }
/// <summary> /// Helper method for the FindAutoCropRectangle /// </summary> /// <param name="buffer"></param> /// <param name="colorPoint"></param> /// <returns></returns> private static Rectangle FindAutoCropRectangle(BitmapBuffer buffer, Point colorPoint, int cropDifference) { Rectangle cropRectangle = Rectangle.Empty; Color referenceColor = buffer.GetColorAtWithoutAlpha(colorPoint.X,colorPoint.Y); Point min = new Point(int.MaxValue, int.MaxValue); Point max = new Point(int.MinValue, int.MinValue); if (cropDifference > 0) { for(int y = 0; y < buffer.Height; y++) { for(int x = 0; x < buffer.Width; x++) { Color currentColor = buffer.GetColorAt(x, y); int diffR = Math.Abs(currentColor.R - referenceColor.R); int diffG = Math.Abs(currentColor.G - referenceColor.G); int diffB = Math.Abs(currentColor.B - referenceColor.B); if (((diffR + diffG + diffB) / 3) > cropDifference) { if (x < min.X) min.X = x; if (y < min.Y) min.Y = y; if (x > max.X) max.X = x; if (y > max.Y) max.Y = y; } } } } else { for(int y = 0; y < buffer.Height; y++) { for(int x = 0; x < buffer.Width; x++) { Color currentColor = buffer.GetColorAtWithoutAlpha(x, y); if (referenceColor.Equals(currentColor)) { if (x < min.X) min.X = x; if (y < min.Y) min.Y = y; if (x > max.X) max.X = x; if (y > max.Y) max.Y = y; } } } } if (!(Point.Empty.Equals(min) && max.Equals(new Point(buffer.Width-1, buffer.Height-1)))) { if (!(min.X == int.MaxValue || min.Y == int.MaxValue || max.X == int.MinValue || min.X == int.MinValue)) { cropRectangle = new Rectangle(min.X, min.Y, max.X - min.X + 1, max.Y - min.Y + 1); } } return cropRectangle; }
public unsafe override void Apply(Graphics graphics, Bitmap applyBitmap, Rectangle rect, RenderMode renderMode) { applyRect = IntersectRectangle(applyBitmap.Size, rect); if (applyRect.Height <= 0 || applyRect.Width <= 0) { return; } int blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); double previewQuality = GetFieldValueAsDouble(FieldType.PREVIEW_QUALITY); // do nothing when nothing can be done! if (blurRadius < 1) { return; } using (BitmapBuffer bbbDest = new BitmapBuffer(applyBitmap, applyRect)) { bbbDest.Lock(); using (BitmapBuffer bbbSrc = new BitmapBuffer(applyBitmap, applyRect)) { bbbSrc.Lock(); Random rand = new Random(); int r = blurRadius; int[] w = CreateGaussianBlurRow(r); int wlen = w.Length; long[] waSums = new long[wlen]; long[] wcSums = new long[wlen]; long[] aSums = new long[wlen]; long[] bSums = new long[wlen]; long[] gSums = new long[wlen]; long[] rSums = new long[wlen]; for (int y = 0; y < applyRect.Height; ++y) { long waSum = 0; long wcSum = 0; long aSum = 0; long bSum = 0; long gSum = 0; long rSum = 0; for (int wx = 0; wx < wlen; ++wx) { int srcX = wx - r; waSums[wx] = 0; wcSums[wx] = 0; aSums[wx] = 0; bSums[wx] = 0; gSums[wx] = 0; rSums[wx] = 0; if (srcX >= 0 && srcX < bbbDest.Width) { for (int wy = 0; wy < wlen; ++wy) { int srcY = y + wy - r; if (srcY >= 0 && srcY < bbbDest.Height) { int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY); int wp = w[wy]; waSums[wx] += wp; wp *= colors[0] + (colors[0] >> 7); wcSums[wx] += wp; wp >>= 8; aSums[wx] += wp * colors[0]; bSums[wx] += wp * colors[3]; gSums[wx] += wp * colors[2]; rSums[wx] += wp * colors[1]; } } int wwx = w[wx]; waSum += wwx * waSums[wx]; wcSum += wwx * wcSums[wx]; aSum += wwx * aSums[wx]; bSum += wwx * bSums[wx]; gSum += wwx * gSums[wx]; rSum += wwx * rSums[wx]; } } wcSum >>= 8; if (waSum == 0 || wcSum == 0) { SetColorAt(bbbDest, 0, y, new int[]{0,0,0,0}); } else { int alpha = (int)(aSum / waSum); int blue = (int)(bSum / wcSum); int green = (int)(gSum / wcSum); int red = (int)(rSum / wcSum); SetColorAt(bbbDest, 0, y, new int[]{alpha, red, green, blue}); } for (int x = 1; x < applyRect.Width; ++x) { for (int i = 0; i < wlen - 1; ++i) { waSums[i] = waSums[i + 1]; wcSums[i] = wcSums[i + 1]; aSums[i] = aSums[i + 1]; bSums[i] = bSums[i + 1]; gSums[i] = gSums[i + 1]; rSums[i] = rSums[i + 1]; } waSum = 0; wcSum = 0; aSum = 0; bSum = 0; gSum = 0; rSum = 0; int wx; for (wx = 0; wx < wlen - 1; ++wx) { long wwx = (long)w[wx]; waSum += wwx * waSums[wx]; wcSum += wwx * wcSums[wx]; aSum += wwx * aSums[wx]; bSum += wwx * bSums[wx]; gSum += wwx * gSums[wx]; rSum += wwx * rSums[wx]; } wx = wlen - 1; waSums[wx] = 0; wcSums[wx] = 0; aSums[wx] = 0; bSums[wx] = 0; gSums[wx] = 0; rSums[wx] = 0; int srcX = x + wx - r; if (srcX >= 0 && srcX < applyRect.Width) { for (int wy = 0; wy < wlen; ++wy) { int srcY = y + wy - r; // only when in EDIT mode, ignore some pixels depending on preview quality if ((renderMode==RenderMode.EXPORT || rand.NextDouble()<previewQuality) && srcY >= 0 && srcY < applyRect.Height) { int[] colors = bbbSrc.GetColorArrayAt(srcX, srcY); int wp = w[wy]; waSums[wx] += wp; wp *= colors[0] + (colors[0] >> 7); wcSums[wx] += wp; wp >>= 8; aSums[wx] += wp * (long)colors[0]; bSums[wx] += wp * (long)colors[3]; gSums[wx] += wp * (long)colors[2]; rSums[wx] += wp * (long)colors[1]; } } int wr = w[wx]; waSum += (long)wr * waSums[wx]; wcSum += (long)wr * wcSums[wx]; aSum += (long)wr * aSums[wx]; bSum += (long)wr * bSums[wx]; gSum += (long)wr * gSums[wx]; rSum += (long)wr * rSums[wx]; } wcSum >>= 8; if (waSum == 0 || wcSum == 0) { SetColorAt(bbbDest, x, y, new int[]{0,0,0,0}); } else { int alpha = (int)(aSum / waSum); int blue = (int)(bSum / wcSum); int green = (int)(gSum / wcSum); int red = (int)(rSum / wcSum); SetColorAt(bbbDest, x, y, new int[]{alpha, red, green, blue}); } } } } bbbDest.DrawTo(graphics, applyRect.Location); } }
/// <summary> /// See <see cref="IColorQuantizer.Prepare"/> for more details. /// </summary> public WuQuantizer(Bitmap sourceBitmap) { this.sourceBitmap = sourceBitmap; // Make sure the color count variables are reset BitArray bitArray = new BitArray((int)Math.Pow(2, 24)); colorCount = 0; // creates all the cubes cubes = new WuColorCube[MAXCOLOR]; // initializes all the cubes for (Int32 cubeIndex = 0; cubeIndex < MAXCOLOR; cubeIndex++) { cubes[cubeIndex] = new WuColorCube(); } // resets the reference minimums cubes[0].RedMinimum = 0; cubes[0].GreenMinimum = 0; cubes[0].BlueMinimum = 0; // resets the reference maximums cubes[0].RedMaximum = MAXSIDEINDEX; cubes[0].GreenMaximum = MAXSIDEINDEX; cubes[0].BlueMaximum = MAXSIDEINDEX; weights = new Int64[SIDESIZE, SIDESIZE, SIDESIZE]; momentsRed = new Int64[SIDESIZE, SIDESIZE, SIDESIZE]; momentsGreen = new Int64[SIDESIZE, SIDESIZE, SIDESIZE]; momentsBlue = new Int64[SIDESIZE, SIDESIZE, SIDESIZE]; moments = new Single[SIDESIZE, SIDESIZE, SIDESIZE]; Int32[] table = new Int32[256]; for (Int32 tableIndex = 0; tableIndex < 256; ++tableIndex) { table[tableIndex] = tableIndex * tableIndex; } // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height, PixelFormat.Format8bppIndexed); using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) { bbbSrc.Lock(); using (BitmapBuffer bbbDest = new BitmapBuffer(resultBitmap, false)) { bbbDest.Lock(); for (int y = 0; y < bbbSrc.Height; y++) { for (int x = 0; x < bbbSrc.Width; x++) { Color color = bbbSrc.GetColorAtWithoutAlpha(x, y); // To count the colors int index = color.ToArgb() & 0x00ffffff; // Check if we already have this color if (!bitArray.Get(index)) { // If not, add 1 to the single colors colorCount++; bitArray.Set(index, true); } Int32 indexRed = (color.R >> 3) + 1; Int32 indexGreen = (color.G >> 3) + 1; Int32 indexBlue = (color.B >> 3) + 1; weights[indexRed, indexGreen, indexBlue]++; momentsRed[indexRed, indexGreen, indexBlue] += color.R; momentsGreen[indexRed, indexGreen, indexBlue] += color.G; momentsBlue[indexRed, indexGreen, indexBlue] += color.B; moments[indexRed, indexGreen, indexBlue] += table[color.R] + table[color.G] + table[color.B]; // Store the initial "match" Int32 paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue; bbbDest.SetColorIndexAt(x, y, (byte)(paletteIndex & 0xff)); } } } } }
/// <summary> /// Get the image /// </summary> public Bitmap GetQuantizedImage(int allowedColorCount) { // preprocess the colors CalculateMoments(); LOG.Info("Calculated the moments..."); Int32 next = 0; Single[] volumeVariance = new Single[MAXCOLOR]; // processes the cubes for (Int32 cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex) { // if cut is possible; make it if (Cut(cubes[next], cubes[cubeIndex])) { volumeVariance[next] = cubes[next].Volume > 1 ? CalculateVariance(cubes[next]) : 0.0f; volumeVariance[cubeIndex] = cubes[cubeIndex].Volume > 1 ? CalculateVariance(cubes[cubeIndex]) : 0.0f; } else { // the cut was not possible, revert the index volumeVariance[next] = 0.0f; cubeIndex--; } next = 0; Single temp = volumeVariance[0]; for (Int32 index = 1; index <= cubeIndex; ++index) { if (volumeVariance[index] > temp) { temp = volumeVariance[index]; next = index; } } if (temp <= 0.0) { allowedColorCount = cubeIndex + 1; break; } } Int32[] lookupRed = new Int32[MAXCOLOR]; Int32[] lookupGreen = new Int32[MAXCOLOR]; Int32[] lookupBlue = new Int32[MAXCOLOR]; tag = new byte[MAXVOLUME]; // precalculates lookup tables for (byte k = 0; k < allowedColorCount; ++k) { Mark(cubes[k], k, tag); long weight = Volume(cubes[k], weights); if (weight > 0) { lookupRed[k] = (int)(Volume(cubes[k], momentsRed) / weight); lookupGreen[k] = (int)(Volume(cubes[k], momentsGreen) / weight); lookupBlue[k] = (int)(Volume(cubes[k], momentsBlue) / weight); } else { lookupRed[k] = 0; lookupGreen[k] = 0; lookupBlue[k] = 0; } } reds = new Int32[allowedColorCount + 1]; greens = new Int32[allowedColorCount + 1]; blues = new Int32[allowedColorCount + 1]; sums = new Int32[allowedColorCount + 1]; LOG.Info("Starting bitmap reconstruction..."); using (BitmapBuffer bbbDest = new BitmapBuffer(resultBitmap, false)) { bbbDest.Lock(); using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) { bbbSrc.Lock(); Dictionary<Color, byte> lookup = new Dictionary<Color, byte>(); byte bestMatch; for (int y = 0; y < bbbSrc.Height; y++) { for (int x = 0; x < bbbSrc.Width; x++) { Color color = bbbSrc.GetColorAtWithoutAlpha(x, y); // Check if we already matched the color if (!lookup.ContainsKey(color)) { // If not we need to find the best match // First get initial match bestMatch = bbbDest.GetColorIndexAt(x, y); bestMatch = tag[bestMatch]; Int32 bestDistance = 100000000; for (byte lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) { Int32 foundRed = lookupRed[lookupIndex]; Int32 foundGreen = lookupGreen[lookupIndex]; Int32 foundBlue = lookupBlue[lookupIndex]; Int32 deltaRed = color.R - foundRed; Int32 deltaGreen = color.G - foundGreen; Int32 deltaBlue = color.B - foundBlue; Int32 distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue; if (distance < bestDistance) { bestDistance = distance; bestMatch = lookupIndex; } } lookup.Add(color, bestMatch); } else { // Already matched, so we just use the lookup bestMatch = lookup[color]; } reds[bestMatch] += color.R; greens[bestMatch] += color.G; blues[bestMatch] += color.B; sums[bestMatch]++; bbbDest.SetColorIndexAt(x, y, bestMatch); } } } } ColorPalette imagePalette = resultBitmap.Palette; // generates palette for (Int32 paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) { if (sums[paletteIndex] > 0) { reds[paletteIndex] /= sums[paletteIndex]; greens[paletteIndex] /= sums[paletteIndex]; blues[paletteIndex] /= sums[paletteIndex]; } imagePalette.Entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); } resultBitmap.Palette = imagePalette; return resultBitmap; }
/// <summary> /// Get the image /// </summary> public Bitmap GetQuantizedImage(int allowedColorCount) { // preprocess the colors CalculateMoments(); LOG.Info("Calculated the moments..."); Int32 next = 0; Single[] volumeVariance = new Single[MAXCOLOR]; // processes the cubes for (Int32 cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex) { // if cut is possible; make it if (Cut(cubes[next], cubes[cubeIndex])) { volumeVariance[next] = cubes[next].Volume > 1 ? CalculateVariance(cubes[next]) : 0.0f; volumeVariance[cubeIndex] = cubes[cubeIndex].Volume > 1 ? CalculateVariance(cubes[cubeIndex]) : 0.0f; } else { // the cut was not possible, revert the index volumeVariance[next] = 0.0f; cubeIndex--; } next = 0; Single temp = volumeVariance[0]; for (Int32 index = 1; index <= cubeIndex; ++index) { if (volumeVariance[index] > temp) { temp = volumeVariance[index]; next = index; } } if (temp <= 0.0) { allowedColorCount = cubeIndex + 1; break; } } Int32[] lookupRed = new Int32[MAXCOLOR]; Int32[] lookupGreen = new Int32[MAXCOLOR]; Int32[] lookupBlue = new Int32[MAXCOLOR]; tag = new byte[MAXVOLUME]; // precalculates lookup tables for (byte k = 0; k < allowedColorCount; ++k) { Mark(cubes[k], k, tag); long weight = Volume(cubes[k], weights); if (weight > 0) { lookupRed[k] = (int)(Volume(cubes[k], momentsRed) / weight); lookupGreen[k] = (int)(Volume(cubes[k], momentsGreen) / weight); lookupBlue[k] = (int)(Volume(cubes[k], momentsBlue) / weight); } else { lookupRed[k] = 0; lookupGreen[k] = 0; lookupBlue[k] = 0; } } reds = new Int32[allowedColorCount + 1]; greens = new Int32[allowedColorCount + 1]; blues = new Int32[allowedColorCount + 1]; sums = new Int32[allowedColorCount + 1]; LOG.Info("Starting bitmap reconstruction..."); using (BitmapBuffer bbbDest = new BitmapBuffer(resultBitmap, false)) { bbbDest.Lock(); using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, false)) { bbbSrc.Lock(); Dictionary <Color, byte> lookup = new Dictionary <Color, byte>(); byte bestMatch; for (int y = 0; y < bbbSrc.Height; y++) { for (int x = 0; x < bbbSrc.Width; x++) { Color color = bbbSrc.GetColorAtWithoutAlpha(x, y); // Check if we already matched the color if (!lookup.ContainsKey(color)) { // If not we need to find the best match // First get initial match bestMatch = bbbDest.GetColorIndexAt(x, y); bestMatch = tag[bestMatch]; Int32 bestDistance = 100000000; for (byte lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) { Int32 foundRed = lookupRed[lookupIndex]; Int32 foundGreen = lookupGreen[lookupIndex]; Int32 foundBlue = lookupBlue[lookupIndex]; Int32 deltaRed = color.R - foundRed; Int32 deltaGreen = color.G - foundGreen; Int32 deltaBlue = color.B - foundBlue; Int32 distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue; if (distance < bestDistance) { bestDistance = distance; bestMatch = lookupIndex; } } lookup.Add(color, bestMatch); } else { // Already matched, so we just use the lookup bestMatch = lookup[color]; } reds[bestMatch] += color.R; greens[bestMatch] += color.G; blues[bestMatch] += color.B; sums[bestMatch]++; bbbDest.SetColorIndexAt(x, y, bestMatch); } } } } ColorPalette imagePalette = resultBitmap.Palette; // generates palette for (Int32 paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) { if (sums[paletteIndex] > 0) { reds[paletteIndex] /= sums[paletteIndex]; greens[paletteIndex] /= sums[paletteIndex]; blues[paletteIndex] /= sums[paletteIndex]; } imagePalette.Entries[paletteIndex] = Color.FromArgb(255, reds[paletteIndex], greens[paletteIndex], blues[paletteIndex]); } resultBitmap.Palette = imagePalette; return(resultBitmap); }