Ejemplo n.º 1
0
		public void Dispose()
		{
			buf.Dispose();
			buf = null;
			bmp.Dispose();
			bmp = null;
		}
Ejemplo n.º 2
0
		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;
            }
        }
Ejemplo n.º 4
0
		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);
            }
        }
Ejemplo n.º 6
0
        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;
            }
        }
Ejemplo n.º 7
0
        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);
        }
Ejemplo n.º 8
0
        /// <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;
        }
Ejemplo n.º 9
0
 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);
     }
 }
Ejemplo n.º 10
0
        /// <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;
            }
        }
Ejemplo n.º 11
0
 /// <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;
     }
 }
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 13
0
        /// <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;
        }
Ejemplo n.º 14
0
        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);
        }
        /// <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));
                        }
                    }
                }
            }
        }