Beispiel #1
0
        protected override Gdk.Rectangle OnMouseMove(Context g, Color strokeColor, ImageSurface surface,
                                                     int x, int y, int lastX, int lastY)
        {
            // Cairo does not support a single-pixel-long single-pixel-wide line
            if (x == lastX && y == lastY && g.LineWidth == 1 &&
                PintaCore.Workspace.ActiveWorkspace.PointInCanvas(new PointD(x, y)))
            {
                surface.Flush();

                ColorBgra source = surface.GetColorBgraUnchecked(x, y);
                source = UserBlendOps.NormalBlendOp.ApplyStatic(source, strokeColor.ToColorBgra());
                surface.SetColorBgra(source.ToPremultipliedAlpha(), x, y);
                surface.MarkDirty();

                return(new Gdk.Rectangle(x - 1, y - 1, 3, 3));
            }

            g.MoveTo(lastX + 0.5, lastY + 0.5);
            g.LineTo(x + 0.5, y + 0.5);
            g.StrokePreserve();

            Gdk.Rectangle dirty = g.FixedStrokeExtents().ToGdkRectangle();

            // For some reason (?!) we need to inflate the dirty
            // rectangle for small brush widths in zoomed images
            dirty.Inflate(1, 1);

            return(dirty);
        }
Beispiel #2
0
        public unsafe override void Render(ImageSurface src, ImageSurface dest, Gdk.Rectangle[] rois)
        {
            dest.Flush();
            foreach (Gdk.Rectangle rect in rois)
            {
                time ^= System.Environment.TickCount;
                time  = time * 17 + 7;
                Random rnd = new Random(time);
                for (int y = rect.Top; y <= rect.GetBottom(); y++)
                {
                    ColorBgra *srcRowPtr    = src.GetPointAddressUnchecked(rect.Left, y);
                    ColorBgra *dstRowPtr    = dest.GetPointAddressUnchecked(rect.Left, y);
                    ColorBgra *dstRowEndPtr = dstRowPtr + rect.Width;

                    while (dstRowPtr < dstRowEndPtr)
                    {
                        ColorBgra col = (*srcRowPtr).ToStraightAlpha();

                        col.A = (byte)(rnd.Next() & 255);
                        *dstRowPtr = col.ToPremultipliedAlpha();
                        ++dstRowPtr;
                        ++srcRowPtr;
                    }
                }
            }
        }
Beispiel #3
0
        private ColorBgra ComputeCellColor(int x, int y, ImageSurface src, int cellSize, Gdk.Rectangle srcBounds)
        {
            Gdk.Rectangle cell = GetCellBox(x, y, cellSize);
            cell.Intersect(srcBounds);

            int left   = cell.Left;
            int right  = cell.GetRight();
            int bottom = cell.GetBottom();
            int top    = cell.Top;

            ColorBgra colorTopLeft     = src.GetColorBgraUnchecked(left, top).ToStraightAlpha();
            ColorBgra colorTopRight    = src.GetColorBgraUnchecked(right, top).ToStraightAlpha();
            ColorBgra colorBottomLeft  = src.GetColorBgraUnchecked(left, bottom).ToStraightAlpha();
            ColorBgra colorBottomRight = src.GetColorBgraUnchecked(right, bottom).ToStraightAlpha();

            ColorBgra c = ColorBgra.BlendColors4W16IP(colorTopLeft, 16384, colorTopRight, 16384, colorBottomLeft, 16384, colorBottomRight, 16384);

            return(c.ToPremultipliedAlpha());
        }
Beispiel #4
0
        public unsafe override void Render(ImageSurface src, ImageSurface dest, Gdk.Rectangle[] rois)
        {
            dest.Flush();
            foreach (Gdk.Rectangle rect in rois)
            {
                for (int y = rect.Top; y <= rect.GetBottom(); y++)
                {
                    ColorBgra *srcRowPtr    = src.GetPointAddressUnchecked(rect.Left, y);
                    ColorBgra *dstRowPtr    = dest.GetPointAddressUnchecked(rect.Left, y);
                    ColorBgra *dstRowEndPtr = dstRowPtr + rect.Width;

                    while (dstRowPtr < dstRowEndPtr)
                    {
                        ColorBgra col = (*srcRowPtr).ToStraightAlpha();

                        col.A = (byte)(((int)(col.R + col.G + col.B)) / 3);

                        *dstRowPtr = col.ToPremultipliedAlpha();
                        ++dstRowPtr;
                        ++srcRowPtr;
                    }
                }
            }
        }
        public unsafe override void Render(ImageSurface src, ImageSurface dest, Gdk.Rectangle[] rois)
        {
            foreach (Gdk.Rectangle rect in rois)
            {
                for (int y = rect.Top; y <= rect.GetBottom(); y++)
                {
                    ColorBgra *srcRowPtr    = src.GetPointAddressUnchecked(rect.Left, y);
                    ColorBgra *dstRowPtr    = dest.GetPointAddressUnchecked(rect.Left, y);
                    ColorBgra *dstRowEndPtr = dstRowPtr + rect.Width;

                    int dither = y & 1;
                    while (dstRowPtr < dstRowEndPtr)
                    {
                        ColorBgra col = (*srcRowPtr).ToStraightAlpha();

                        dither++;
                        int r = col.R, g = col.G, b = col.B;;

                        if ((dither & 1) == 0)
                        {
                            r += 2;
                            g += 2;
                            b += 2;
                            if (r > 255)
                            {
                                r = 255;
                            }
                            if (g > 255)
                            {
                                g = 255;
                            }
                            if (b > 255)
                            {
                                b = 255;
                            }
                        }
                        else
                        {
                            r -= 2;
                            g -= 2;
                            b -= 2;
                            if (r < 0)
                            {
                                r = 0;
                            }
                            if (g < 0)
                            {
                                g = 0;
                            }
                            if (b < 0)
                            {
                                b = 0;
                            }
                        }
                        col.R = (byte)r;
                        col.G = (byte)g;
                        col.B = (byte)b;
                        *dstRowPtr = col.ToPremultipliedAlpha();
                        ++dstRowPtr;
                        ++srcRowPtr;
                    }
                }
            }
        }
Beispiel #6
0
        protected override unsafe Gdk.Rectangle OnMouseMove(Context g, Color strokeColor, ImageSurface surface,
                                                            int x, int y, int lastX, int lastY)
        {
            int rad = (int)(g.LineWidth / 2.0 + 0.5);

            if (rad < 2)
            {
                rad = 2;
            }

            Gdk.Rectangle surface_rect = new Gdk.Rectangle(0, 0, surface.Width, surface.Height);
            Gdk.Rectangle brush_rect   = new Gdk.Rectangle(x - rad, y - rad, 2 * rad, 2 * rad);
            Gdk.Rectangle dest_rect    = Gdk.Rectangle.Intersect(surface_rect, brush_rect);

            if ((dest_rect.Width > 1) && (dest_rect.Height > 1))
            {
                //Allow Clipping through a temporary surface
                ImageSurface tmp_surface = new ImageSurface(Format.Argb32, dest_rect.Width, dest_rect.Height);

                using (Context g2 = new Context(tmp_surface)) {
                    g2.Operator = Operator.Source;
                    g2.SetSourceSurface(surface, -dest_rect.Left, -dest_rect.Top);
                    g2.Rectangle(new Rectangle(0, 0, dest_rect.Width, dest_rect.Height));
                    g2.Fill();
                }

                //Flush to make sure all drawing operations are finished
                tmp_surface.Flush();
                ColorBgra[,] tmp = new ColorBgra[dest_rect.Width, dest_rect.Height];

                for (int iy = 0; iy < dest_rect.Height; iy++)
                {
                    ColorBgra *srcRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy);
                    for (int ix = 0; ix < dest_rect.Width; ix++)
                    {
                        tmp[ix, iy] = (*srcRowPtr).ToStraightAlpha();
                        srcRowPtr++;
                    }
                }

                for (int iy = 1; iy < dest_rect.Height - 1; iy++)
                {
                    ColorBgra *dstRowPtr = tmp_surface.GetPointAddressUnchecked(1, iy);
                    int        dy        = dest_rect.Top + iy - y;
                    for (int ix = 1; ix < dest_rect.Width - 1; ix++)
                    {
                        int dx = dest_rect.Left + ix - x;

                        if ((dx * dx + dy * dy) < rad * rad)
                        {
                            ColorBgra col = ColorBgra.Black;
                            col.R = (byte)((2 * tmp[ix, iy].R + tmp[ix - 1, iy].R + tmp[ix + 1, iy].R + tmp[ix, iy - 1].R + tmp[ix, iy + 1].R + 3) / 6);
                            col.G = (byte)((2 * tmp[ix, iy].G + tmp[ix - 1, iy].G + tmp[ix + 1, iy].G + tmp[ix, iy - 1].G + tmp[ix, iy + 1].G + 3) / 6);
                            col.B = (byte)((2 * tmp[ix, iy].B + tmp[ix - 1, iy].B + tmp[ix + 1, iy].B + tmp[ix, iy - 1].B + tmp[ix, iy + 1].B + 3) / 6);
                            col.A = (byte)((2 * tmp[ix, iy].A + tmp[ix - 1, iy].A + tmp[ix + 1, iy].A + tmp[ix, iy - 1].A + tmp[ix, iy + 1].A + 3) / 6);
                            *dstRowPtr = col.ToPremultipliedAlpha();
                        }
                        dstRowPtr++;
                    }
                }

                //Draw the final result on the surface
                g.Operator = Operator.Source;
                g.SetSourceSurface(tmp_surface, dest_rect.Left, dest_rect.Top);
                g.Rectangle(new Rectangle(dest_rect.Left, dest_rect.Top, dest_rect.Width, dest_rect.Height));
                g.Fill();
            }
            return(Gdk.Rectangle.Zero);
        }
        protected override unsafe Gdk.Rectangle OnMouseMove(Context g, Color strokeColor, ImageSurface surface,
                                                            int x, int y, int lastX, int lastY)
        {
            int rad = (int)(g.LineWidth / 2.0) + 1;

            Gdk.Rectangle surface_rect = new Gdk.Rectangle(0, 0, surface.Width, surface.Height);
            Gdk.Rectangle brush_rect   = new Gdk.Rectangle(x - rad, y - rad, 2 * rad, 2 * rad);
            Gdk.Rectangle dest_rect    = Gdk.Rectangle.Intersect(surface_rect, brush_rect);

            //Initialize lookup table when first used (to prevent slower startup of the application)
            if (lut_factor == null)
            {
                lut_factor = new byte[LUT_Resolution + 1, LUT_Resolution + 1];

                for (int dy = 0; dy < LUT_Resolution + 1; dy++)
                {
                    for (int dx = 0; dx < LUT_Resolution + 1; dx++)
                    {
                        double d = Math.Sqrt(dx * dx + dy * dy) / LUT_Resolution;
                        if (d > 1.0)
                        {
                            lut_factor [dx, dy] = 0;
                        }
                        else
                        {
                            lut_factor [dx, dy] = (byte)(Math.Cos(Math.Sqrt(d) * Math.PI / 2.0) * 255.0);
                        }
                    }
                }
            }

            if ((dest_rect.Width > 0) && (dest_rect.Height > 0))
            {
                //Allow Clipping through a temporary surface
                ImageSurface tmp_surface = new ImageSurface(Format.Argb32, dest_rect.Width, dest_rect.Height);

                using (Context g2 = new Context(tmp_surface)) {
                    g2.Operator = Operator.Source;
                    g2.SetSourceSurface(surface, -dest_rect.Left, -dest_rect.Top);
                    g2.Rectangle(new Rectangle(0, 0, dest_rect.Width, dest_rect.Height));
                    g2.Fill();
                }

                //Flush to make sure all drawing operations are finished
                tmp_surface.Flush();


                int mean_r = 0, mean_g = 0, mean_b = 0;
                int max_diff_r = 1, max_diff_g = 1, max_diff_b = 1;
                int sz = 0;

                byte[,] factors = new byte[dest_rect.Right - dest_rect.Left, dest_rect.Bottom - dest_rect.Top];

                for (int iy = dest_rect.Top; iy < dest_rect.Bottom; iy++)
                {
                    ColorBgra *srcRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy - dest_rect.Top);
                    for (int ix = dest_rect.Left; ix < dest_rect.Right; ix++)
                    {
                        ColorBgra col = (*srcRowPtr).ToStraightAlpha();
                        int       dx  = ((ix - x) * LUT_Resolution) / rad;
                        if (dx < 0)
                        {
                            dx = -dx;
                        }
                        int dy = ((iy - y) * LUT_Resolution) / rad;
                        if (dy < 0)
                        {
                            dy = -dy;
                        }

                        int factor = lut_factor[dx, dy];
                        sz     += factor;
                        mean_r += col.R * factor;
                        mean_g += col.G * factor;
                        mean_b += col.B * factor;
                        srcRowPtr++;
                    }
                }
                if (sz > 0)
                {
                    mean_r /= sz;
                    mean_g /= sz;
                    mean_b /= sz;
                }

                for (int iy = dest_rect.Top; iy < dest_rect.Bottom; iy++)
                {
                    ColorBgra *srcRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy - dest_rect.Top);
                    for (int ix = dest_rect.Left; ix < dest_rect.Right; ix++)
                    {
                        ColorBgra col = (*srcRowPtr).ToStraightAlpha();
                        int       dr  = col.R - mean_r;
                        int       dg  = col.G - mean_g;
                        int       db  = col.B - mean_b;

                        if (dr < 0)
                        {
                            dr = -dr;
                        }
                        if (dg < 0)
                        {
                            dg = -dg;
                        }
                        if (db < 0)
                        {
                            db = -db;
                        }

                        if (dr > max_diff_r)
                        {
                            max_diff_r = dr;
                        }
                        if (dg > max_diff_g)
                        {
                            max_diff_g = dg;
                        }
                        if (db > max_diff_b)
                        {
                            max_diff_b = db;
                        }
                        srcRowPtr++;
                    }
                }

                for (int iy = dest_rect.Top; iy < dest_rect.Bottom; iy++)
                {
                    ColorBgra *srcRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy - dest_rect.Top);
                    int        dy        = ((iy - y) * LUT_Resolution) / rad;
                    if (dy < 0)
                    {
                        dy = -dy;
                    }

                    for (int ix = dest_rect.Left; ix < dest_rect.Right; ix++)
                    {
                        ColorBgra col = (*srcRowPtr).ToStraightAlpha();
                        int       dx  = ((ix - x) * LUT_Resolution) / rad;
                        if (dx < 0)
                        {
                            dx = -dx;
                        }

                        int dr = ((col.R - mean_r) * 2 * LUT_Resolution) / max_diff_r;
                        int dg = ((col.G - mean_g) * 2 * LUT_Resolution) / max_diff_g;
                        int db = ((col.B - mean_b) * 2 * LUT_Resolution) / max_diff_b;

                        if (dr < 0)
                        {
                            dr = -dr;
                        }
                        if (dg < 0)
                        {
                            dg = -dg;
                        }
                        if (db < 0)
                        {
                            db = -db;
                        }

                        if (dr > LUT_Resolution)
                        {
                            dr = LUT_Resolution;
                        }
                        if (dg > LUT_Resolution)
                        {
                            dg = LUT_Resolution;
                        }
                        if (db > LUT_Resolution)
                        {
                            db = LUT_Resolution;
                        }

                        int factor;

                        if ((max_diff_r > 32) || (max_diff_g > 32) || (max_diff_b > 32))
                        {
                            factor = lut_factor[dx, dy] * lut_factor[dg, (dr + db) / 2];
                            col.A  = (byte)((col.A * (0xFFFF - factor)) / 0xFFFF);
                        }
                        else
                        {
                            factor = lut_factor[dx, dy];
                            col.A  = (byte)((col.A * (0xFF - factor)) / 0xFF);
                        }

                        *srcRowPtr = col.ToPremultipliedAlpha();
                        srcRowPtr++;
                    }
                }
                //Draw the final result on the surface
                g.Operator = Operator.Source;
                g.SetSourceSurface(tmp_surface, dest_rect.Left, dest_rect.Top);
                g.Rectangle(new Rectangle(dest_rect.Left, dest_rect.Top, dest_rect.Width, dest_rect.Height));
                g.Fill();
            }
            return(Gdk.Rectangle.Zero);
        }
Beispiel #8
0
        private void Draw(DrawingArea drawingarea1, Color tool_color, Cairo.PointD point, bool first_pixel)
        {
            int x = (int)point.X;
            int y = (int)point.Y;

            if (last_point.Equals(point_empty))
            {
                last_point = new Point(x, y);

                if (!first_pixel)
                {
                    return;
                }
            }

            Document doc = PintaCore.Workspace.ActiveDocument;

            if (doc.Workspace.PointInCanvas(point))
            {
                surface_modified = true;
            }

            ImageSurface surf = doc.CurrentUserLayer.Surface;

            if (first_pixel && doc.Workspace.PointInCanvas(point))
            {
                // Does Cairo really not support a single-pixel-long single-pixel-wide line?
                surf.Flush();
                int       shiftedX = (int)point.X;
                int       shiftedY = (int)point.Y;
                ColorBgra source   = surf.GetColorBgraUnchecked(shiftedX, shiftedY);
                if (UseAlphaBlending)
                {
                    source = UserBlendOps.NormalBlendOp.ApplyStatic(source, tool_color.ToColorBgra());
                }
                else
                {
                    source = tool_color.ToColorBgra();
                }
                surf.SetColorBgra(source.ToPremultipliedAlpha(), shiftedX, shiftedY);
                surf.MarkDirty();
            }
            else
            {
                using (Context g = new Context(surf)) {
                    g.AppendPath(doc.Selection.SelectionPath);
                    g.FillRule = FillRule.EvenOdd;
                    g.Clip();

                    g.Antialias = Antialias.None;

                    // Adding 0.5 forces cairo into the correct square:
                    // See https://bugs.launchpad.net/bugs/672232
                    g.MoveTo(last_point.X + 0.5, last_point.Y + 0.5);
                    g.LineTo(x + 0.5, y + 0.5);

                    g.SetSourceColor(tool_color);
                    if (UseAlphaBlending)
                    {
                        g.SetBlendMode(BlendMode.Normal);
                    }
                    else
                    {
                        g.Operator = Operator.Source;
                    }
                    g.LineWidth = 1;
                    g.LineCap   = LineCap.Square;

                    g.Stroke();
                }
            }

            Gdk.Rectangle r = GetRectangleFromPoints(last_point, new Point(x, y));

            doc.Workspace.Invalidate(doc.ClampToImageSize(r));

            last_point = new Point(x, y);
        }
        protected override unsafe Gdk.Rectangle OnMouseMove(Context g, Color strokeColor, ImageSurface surface,
                                                            int x, int y, int lastX, int lastY)
        {
            int rad = (int)(g.LineWidth / 2.0) + 1;

            int stroke_a = (int)(255.0 * strokeColor.A);
            int stroke_r = (int)(255.0 * strokeColor.R);
            int stroke_g = (int)(255.0 * strokeColor.G);
            int stroke_b = (int)(255.0 * strokeColor.B);

            int stroke_cb = (-173 * stroke_r - 339 * stroke_g + 512 * stroke_b) >> 9;
            int stroke_cr = (512 * stroke_r - 429 * stroke_g - 83 * stroke_b) >> 9;

            Gdk.Rectangle surface_rect = new Gdk.Rectangle(0, 0, surface.Width, surface.Height);
            Gdk.Rectangle brush_rect   = new Gdk.Rectangle(x - rad, y - rad, 2 * rad, 2 * rad);
            Gdk.Rectangle dest_rect    = Gdk.Rectangle.Intersect(surface_rect, brush_rect);


            //Initialize lookup table when first used (to prevent slower startup of the application)
            if (lut_factor == null)
            {
                lut_factor = new byte[LUT_Resolution + 1, LUT_Resolution + 1];

                for (int dy = 0; dy < LUT_Resolution + 1; dy++)
                {
                    for (int dx = 0; dx < LUT_Resolution + 1; dx++)
                    {
                        double d = Math.Sqrt(dx * dx + dy * dy) / LUT_Resolution;
                        if (d > 1.0)
                        {
                            lut_factor [dx, dy] = 0;
                        }
                        else
                        {
                            lut_factor [dx, dy] = (byte)(Math.Cos(Math.Sqrt(d) * Math.PI / 2.0) * 255);
                        }
                    }
                }
            }

            if ((dest_rect.Width > 0) && (dest_rect.Height > 0))
            {
                //Allow Clipping through a temporary surface
                ImageSurface tmp_surface = new ImageSurface(Format.Argb32, dest_rect.Width, dest_rect.Height);

                using (Context g2 = new Context(tmp_surface)) {
                    g2.Operator = Operator.Source;
                    g2.SetSourceSurface(surface, -dest_rect.Left, -dest_rect.Top);
                    g2.Rectangle(new Rectangle(0, 0, dest_rect.Width, dest_rect.Height));
                    g2.Fill();
                }

                //Flush to make sure all drawing operations are finished
                tmp_surface.Flush();

                for (int iy = dest_rect.Top; iy < dest_rect.Bottom; iy++)
                {
                    ColorBgra *srcRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy - dest_rect.Top);
                    int        dy        = ((iy - y) * LUT_Resolution) / rad;
                    if (dy < 0)
                    {
                        dy = -dy;
                    }
                    for (int ix = dest_rect.Left; ix < dest_rect.Right; ix++)
                    {
                        ColorBgra col = (*srcRowPtr).ToStraightAlpha();
                        int       dx  = ((ix - x) * LUT_Resolution) / rad;
                        if (dx < 0)
                        {
                            dx = -dx;
                        }

                        int force = (lut_factor[dx, dy] * stroke_a);
                        int col_y = (306 * col.R + 601 * col.G + 117 * col.B + 256) >> 9;

                        int red   = (256 * col_y + 359 * stroke_cr + 256) >> 9;
                        int green = (256 * col_y - 88 * stroke_cb - 183 * stroke_cr + 256) >> 9;
                        int blue  = (256 * col_y + 454 * stroke_cb + 256) >> 9;

                        if (red > 255)
                        {
                            red = 255;
                        }
                        if (red < 0)
                        {
                            red = 0;
                        }
                        if (green > 255)
                        {
                            green = 255;
                        }
                        if (green < 0)
                        {
                            green = 0;
                        }
                        if (blue > 255)
                        {
                            blue = 255;
                        }
                        if (blue < 0)
                        {
                            blue = 0;
                        }

                        col.R = (byte)((col.R * (255 * 255 - force) + red * force + 32512) / (255 * 255));
                        col.G = (byte)((col.G * (255 * 255 - force) + green * force + 32512) / (255 * 255));
                        col.B = (byte)((col.B * (255 * 255 - force) + blue * force + 32512) / (255 * 255));

                        *srcRowPtr = col.ToPremultipliedAlpha();
                        srcRowPtr++;
                    }
                }
                //Draw the final result on the surface
                g.Operator = Operator.Source;
                g.SetSourceSurface(tmp_surface, dest_rect.Left, dest_rect.Top);
                g.Rectangle(new Rectangle(dest_rect.Left, dest_rect.Top, dest_rect.Width, dest_rect.Height));
                g.Fill();
            }
            return(Gdk.Rectangle.Zero);
        }
Beispiel #10
0
        protected override unsafe Gdk.Rectangle OnMouseMove(Context g, Color strokeColor, ImageSurface surface,
                                                            int x, int y, int lastX, int lastY)
        {
            int rad = (int)(g.LineWidth / 2.0 + 0.5);

            rad /= 2;
            rad *= 2;
            if (rad < 2)
            {
                rad = 2;
            }


            //Initialize lookup table when first used (to prevent slower startup of the application)
            if (lut_factor == null)
            {
                lut_factor = new byte[LUT_Resolution + 1, LUT_Resolution + 1];

                for (int dy = 0; dy < LUT_Resolution + 1; dy++)
                {
                    for (int dx = 0; dx < LUT_Resolution + 1; dx++)
                    {
                        double d = Math.Sqrt(dx * dx + dy * dy) / LUT_Resolution;
                        if (d > 1.0)
                        {
                            lut_factor [dx, dy] = 0;
                        }
                        else
                        {
                            lut_factor [dx, dy] = (byte)(Math.Cos(Math.Sqrt(d) * Math.PI / 2.0) * 255.0);
                        }
                    }
                }
            }

            Gdk.Rectangle surface_rect = new Gdk.Rectangle(0, 0, surface.Width, surface.Height);
            Gdk.Rectangle brush_rect   = new Gdk.Rectangle(x - rad, y - rad, 2 * rad, 2 * rad);
            Gdk.Rectangle dest_rect    = Gdk.Rectangle.Intersect(surface_rect, brush_rect);

            if ((dest_rect.Width > 1) && (dest_rect.Height > 1))
            {
                //Allow Clipping through a temporary surface
                ImageSurface tmp_surface = new ImageSurface(Format.Argb32, dest_rect.Width, dest_rect.Height);

                using (Context g2 = new Context(tmp_surface)) {
                    g2.Operator = Operator.Source;
                    g2.SetSourceSurface(surface, -dest_rect.Left, -dest_rect.Top);
                    g2.Rectangle(new Rectangle(0, 0, dest_rect.Width, dest_rect.Height));
                    g2.Fill();
                }

                //Flush to make sure all drawing operations are finished
                tmp_surface.Flush();

                int[,] mean_r = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1];
                int[,] mean_g = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1];
                int[,] mean_b = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1];
                int[,] mean_a = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1];
                int[,] mean_c = new int[dest_rect.Width / 2 + 1, dest_rect.Height / 2 + 1];

                for (int iy = 0; iy < dest_rect.Height / 2; iy++)
                {
                    for (int ix = 0; ix < dest_rect.Width / 2; ix++)
                    {
                        mean_a[ix, iy] = 0;
                        mean_r[ix, iy] = 0;
                        mean_g[ix, iy] = 0;
                        mean_b[ix, iy] = 0;
                        mean_c[ix, iy] = 0;
                    }
                }

                for (int iy = 0; iy < dest_rect.Height; iy++)
                {
                    ColorBgra *srcRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy);
                    for (int ix = 0; ix < dest_rect.Width; ix++)
                    {
                        ColorBgra col = (*srcRowPtr).ToStraightAlpha();
                        int       pos_x = ix >> 1, pos_y = iy >> 1;
                        mean_r[pos_x, pos_y] += col.R;
                        mean_g[pos_x, pos_y] += col.G;
                        mean_b[pos_x, pos_y] += col.B;
                        mean_a[pos_x, pos_y] += col.A;
                        mean_c[pos_x, pos_y]++;
                        srcRowPtr++;
                    }
                }

                for (int iy = 0; iy < dest_rect.Height; iy++)
                {
                    ColorBgra *dstRowPtr = tmp_surface.GetPointAddressUnchecked(0, iy);
                    int        dy        = ((iy + dest_rect.Top - y) * LUT_Resolution) / rad;
                    if (dy < 0)
                    {
                        dy = -dy;
                    }

                    for (int ix = 0; ix < dest_rect.Width; ix++)
                    {
                        ColorBgra col = (*dstRowPtr).ToStraightAlpha();

                        int dx = ((ix + dest_rect.Left - x) * LUT_Resolution) / rad;
                        if (dx < 0)
                        {
                            dx = -dx;
                        }

                        int factor = lut_factor[dx, dy];

                        int pos_x = ix >> 1, pos_y = iy >> 1;
                        int count = mean_c[pos_x, pos_y];

                        int red   = col.R + (col.R - mean_r[pos_x, pos_y] / count);
                        int green = col.G + (col.G - mean_g[pos_x, pos_y] / count);
                        int blue  = col.B + (col.B - mean_b[pos_x, pos_y] / count);
                        int alpha = col.A + (col.A - mean_a[pos_x, pos_y] / count);

                        /*
                         * int diff_red   = (4*red   - tmp[ix-1,iy].R - tmp[ix,iy-1].R - tmp[ix+1,iy].R - tmp[ix,iy+1].R)/4;
                         * int diff_green = (4*green - tmp[ix-1,iy].G - tmp[ix,iy-1].G - tmp[ix+1,iy].G - tmp[ix,iy+1].G)/4;
                         * int diff_blue  = (4*blue  - tmp[ix-1,iy].B - tmp[ix,iy-1].B - tmp[ix+1,iy].B - tmp[ix,iy+1].B)/4;
                         * int diff_alpha = (4*alpha  - tmp[ix-1,iy].A - tmp[ix,iy-1].A - tmp[ix+1,iy].A - tmp[ix,iy+1].A)/4;
                         */
                        //red -= diff_red;
                        //if ((red & 255) != 0) { //Negative or grater than 255
                        if (red > 255)
                        {
                            red = 255;
                        }
                        if (red < 0)
                        {
                            red = 0;
                        }
                        //}
                        //green -= diff_green;
                        //if ((green & 255) != 0) { //Negative or grater than 255
                        if (green > 255)
                        {
                            green = 255;
                        }
                        if (green < 0)
                        {
                            green = 0;
                        }
                        //}
                        //blue -= diff_blue;
                        //if ((blue & 255) != 0) { //Negative or grater than 255
                        if (blue > 255)
                        {
                            blue = 255;
                        }
                        if (blue < 0)
                        {
                            blue = 0;
                        }
                        //}
                        //alpha -= diff_alpha;
                        //if ((alpha & 255) != 0) { //Negative or grater than 255
                        if (alpha > 255)
                        {
                            alpha = 255;
                        }
                        if (alpha < 0)
                        {
                            alpha = 0;
                        }
                        col.R = (byte)((red * factor + col.R * (512 - factor)) >> 9);
                        col.G = (byte)((green * factor + col.G * (512 - factor)) >> 9);
                        col.B = (byte)((blue * factor + col.B * (512 - factor)) >> 9);
                        col.A = (byte)((alpha * factor + col.A * (512 - factor)) >> 9);
                        *dstRowPtr = col.ToPremultipliedAlpha();

                        dstRowPtr++;
                    }
                }

                //Draw the final result on the surface
                g.Operator = Operator.Source;
                g.SetSourceSurface(tmp_surface, dest_rect.Left, dest_rect.Top);
                g.Rectangle(new Rectangle(dest_rect.Left, dest_rect.Top, dest_rect.Width, dest_rect.Height));
                g.Fill();
            }
            return(Gdk.Rectangle.Zero);
        }