示例#1
0
        private void Image_Loaded(object sender, RoutedEventArgs e)
        {
            Image image = (Image)sender;

            using (ImageSurface surface = new ImageSurface(Format.Argb32, (int)image.Width, (int)image.Height))
            {
                using (Context context = new Context(surface))
                {
                    PointD p  = new PointD(10.0, 10.0);
                    PointD p2 = new PointD(100.0, 10.0);
                    PointD p3 = new PointD(100.0, 100.0);
                    PointD p4 = new PointD(10.0, 100.0);
                    context.MoveTo(p);
                    context.LineTo(p2);
                    context.LineTo(p3);
                    context.LineTo(p4);
                    context.LineTo(p);
                    context.ClosePath();
                    context.Fill();
                    context.MoveTo(140.0, 110.0);
                    context.SetFontSize(32.0);
                    context.SetSourceColor(new Color(0.0, 0.0, 0.8, 1.0));
                    context.ShowText("Hello Cairo!");
                    surface.Flush();
                    RgbaBitmapSource source = new RgbaBitmapSource(surface.Data, surface.Width);
                    image.Source = source;
                }
            }
        }
示例#2
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, 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);
        }
示例#3
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;
                    }
                }
            }
        }
示例#4
0
        private Pixbuf ProcessImpl(Pixbuf input, Cms.Profile input_profile, bool fast)
        {
            Pixbuf result;

            using (ImageInfo info = new ImageInfo(input)) {
                using (ImageSurface surface = new ImageSurface(Format.Argb32,
                                                               input.Width,
                                                               input.Height)) {
                    using (Context ctx = new Context(surface)) {
                        ctx.Matrix = info.Fill(info.Bounds, angle);
                        using (SurfacePattern p = new SurfacePattern(info.Surface)) {
                            if (fast)
                            {
                                p.Filter = Filter.Fast;
                            }
                            ctx.Source = p;
                            ctx.Paint();
                        }
                        result = surface.ToPixbuf();
                        surface.Flush();
                    }
                }
            }
            return(result);
        }
示例#5
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)
                    {
                        //ToStraightAlpha() and ToPremultipliedAlpha() are not needed here
                        ColorBgra col = (*srcRowPtr);

                        col.R = col.A;
                        col.G = col.A;
                        col.B = col.A;
                        col.A = 255;

                        *dstRowPtr = col;
                        ++dstRowPtr;
                        ++srcRowPtr;
                    }
                }
            }
        }
示例#6
0
        void updateGraphic(string file)
        {
            int width  = 100;
            int height = 15;
            int x      = 10;
            int y      = 6;

            Bitmap     bmp  = new Bitmap(file);
            BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(x, y, width, height),
                                           ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            int stride = 4 * width;

            using (ImageSurface draw =
                       new ImageSurface(data.Scan0, Format.Argb32, width, height, stride))
            {
                using (Context gr = new Context(draw))
                {
                    //Rectangle r = new Rectangle(0, 0, renderBounds.Width, renderBounds.Height);
                    gr.SelectFontFace("MagicMedieval", FontSlant.Normal, FontWeight.Bold);
                    gr.SetFontSize(12);
                    gr.SetSourceColor(Crow.Color.Black);

                    string test = "Test string";

                    FontExtents fe = gr.FontExtents;
                    TextExtents te = gr.TextExtents(test);
                    double      xt = 20;// 0.5 - te.XBearing - te.Width / 2,
                    double      yt = fe.Height;

                    gr.MoveTo(xt, yt);
                    gr.ShowText(test);

                    using (ImageSurface imgSurf = new ImageSurface(@"images/manaw.png"))
                    {
                        gr.SetSourceSurface(imgSurf, 0, 0);

                        gr.Paint();
                    }
                    draw.Flush();
                }
                //draw.WriteToPng(directories.rootDir + @"test.png");
            }


            imgHelpers.imgHelpers.flipY(data.Scan0, stride, height);

            GL.TexSubImage2D(TextureTarget.Texture2D, 0, x, bmp.Height - y - height, width, height,
                             OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);

            bmp.UnlockBits(data);
        }
示例#7
0
        private ImageSurface copySurfacePart(ImageSurface surf, Gdk.Rectangle dest_rect)
        {
            ImageSurface tmp_surface = new ImageSurface(Format.Argb32, dest_rect.Width, dest_rect.Height);

            using (Context g = new Context(tmp_surface)) {
                g.Operator = Operator.Source;
                g.SetSourceSurface(surf, -dest_rect.Left, -dest_rect.Top);
                g.Rectangle(new Rectangle(0, 0, dest_rect.Width, dest_rect.Height));
                g.Fill();
            }
            //Flush to make sure all drawing operations are finished
            tmp_surface.Flush();
            return(tmp_surface);
        }
示例#8
0
        protected unsafe override void OnFillRegionComputed(IBitVector2D stencil)
        {
            Document     doc  = PintaCore.Workspace.ActiveDocument;
            ImageSurface surf = doc.ToolLayer.Surface;

            using (var g = new Context(surf)) {
                g.Operator = Operator.Source;
                g.SetSource(doc.CurrentUserLayer.Surface);
                g.Paint();
            }

            SimpleHistoryItem hist = new SimpleHistoryItem(Icon, Name);

            hist.TakeSnapshotOfLayer(doc.CurrentUserLayer);

            ColorBgra  color  = fill_color.ToColorBgra().ToPremultipliedAlpha();
            ColorBgra *dstPtr = (ColorBgra *)surf.DataPtr;
            int        width  = surf.Width;

            surf.Flush();

            // Color in any pixel that the stencil says we need to fill
            Parallel.For(0, stencil.Height, y =>
            {
                int stencil_width = stencil.Width;
                for (int x = 0; x < stencil_width; ++x)
                {
                    if (stencil.GetUnchecked(x, y))
                    {
                        surf.SetColorBgraUnchecked(dstPtr, width, color, x, y);
                    }
                }
            });

            surf.MarkDirty();

            // Transfer the temp layer to the real one,
            // respecting any selection area
            using (var g = doc.CreateClippedContext()) {
                g.Operator = Operator.Source;
                g.SetSource(surf);
                g.Paint();
            }

            doc.ToolLayer.Clear();

            doc.History.PushNewItem(hist);
            doc.Workspace.Invalidate();
        }
示例#9
0
		/// <summary>
		/// Internal drawing context creation on a cached surface limited to slot size
		/// this trigger the effective drawing routine </summary>
		protected virtual void RecreateCache ()
		{
			int stride = 4 * Slot.Width;

			int bmpSize = Math.Abs (stride) * Slot.Height;
			bmp = new byte[bmpSize];
			IsDirty = false;
			using (ImageSurface draw =
                new ImageSurface(bmp, Format.Argb32, Slot.Width, Slot.Height, stride)) {
				using (Context gr = new Context (draw)) {
					gr.Antialias = Interface.Antialias;
					onDraw (gr);
				}
				draw.Flush ();
			}
		}
示例#10
0
        public static Color GetPixel(this ImageSurface sf, int x, int y)
        {
            int pixelSize;

            switch (sf.Format)
            {
            case Format.Argb32:
                pixelSize = 4;
                break;

            case Format.Rgb24:
                pixelSize = 3;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            sf.Flush();
            int start = x * pixelSize + y * sf.Stride;

            byte [] data = sf.Data;

            switch (sf.Format)
            {
            case Format.Argb32:
                return(new Color(
                           data [start + 1] / 255.0,
                           data [start + 2] / 255.0,
                           data [start + 3] / 255.0,
                           data [start + 0] / 255.0));

            case Format.Rgb24:
                return(new Color(
                           data [start + 0] / 255.0,
                           data [start + 1] / 255.0,
                           data [start + 2] / 255.0));

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#11
0
        private unsafe void ApplyAndSwap(ImageSurface dst, bool swap)
        {
            dst.Flush();

            var       dest_width = dst.Width;
            var       dst_ptr    = (ColorBgra *)dst.DataPtr;
            var       mask_index = 0;
            ColorBgra swap_pixel;

            fixed(ColorBgra *fixed_ptr = pixels)
            {
                var pixel_ptr = fixed_ptr;

                dst_ptr += bounds.X + bounds.Y * dest_width;

                for (int y = bounds.Y; y <= bounds.GetBottom(); y++)
                {
                    for (int x = bounds.X; x <= bounds.GetRight(); x++)
                    {
                        if (bitmask[mask_index++])
                        {
                            if (swap)
                            {
                                swap_pixel = *dst_ptr;
                                *dst_ptr     = *pixel_ptr;
                                *pixel_ptr++ = swap_pixel;
                            }
                            else
                            {
                                *dst_ptr = *pixel_ptr++;
                            }
                        }

                        dst_ptr++;
                    }

                    dst_ptr += dest_width - bounds.Width;
                }
            }

            dst.MarkDirty();
        }
示例#12
0
        Pixbuf ProcessImpl(Pixbuf input, Cms.Profile inputProfile, bool fast)
        {
            Pixbuf result;

            using (var info = new ImageInfo(input)) {
                using (var soft = new SoftFocus(info)) {
                    soft.Radius = radius;

                    using (var surface = new ImageSurface(Format.Argb32, input.Width, input.Height)) {
                        using (var ctx = new Context(surface)) {
                            soft.Apply(ctx, info.Bounds);
                        }

                        result = surface.ToPixbuf();
                        surface.Flush();
                    }
                }
            }
            return(result);
        }
示例#13
0
        protected override void RecreateCache()
        {
            lock (mutex) {
                int stride = 4 * Slot.Width;

                int bmpSize = Math.Abs(stride) * Slot.Height;
                if (lastVisibleLines > 0)
                {
                    byte[] newBmp = new byte[bmpSize];

                    using (ImageSurface draw =
                               new ImageSurface(newBmp, Format.Argb32, Slot.Width, Slot.Height, stride)) {
                        using (Context gr = new Context(draw)) {
                            using (ImageSurface lastDraw =
                                       new ImageSurface(bmp, Format.Argb32, LastPaintedSlot.Width, LastPaintedSlot.Height,
                                                        LastPaintedSlot.Width * 4)) {
                                gr.SetSource(lastDraw, 0, (lastScroll - scroll) * lineHeight);
                                gr.Paint();
                            }
                        }
                    }
                    bmp = newBmp;
                }
                else
                {
                    bmp = new byte[bmpSize];
                }
                IsDirty = false;

                using (ImageSurface draw =
                           new ImageSurface(bmp, Format.Argb32, Slot.Width, Slot.Height, stride)) {
                    using (Context gr = new Context(draw)) {
                        gr.Antialias = Interface.Antialias;
                        onDraw(gr);
                    }
                    draw.Flush();
                }
            }
        }
示例#14
0
        static void Main(string[] args)
        {
            int height  = 512;
            int width   = 512;
            int stride  = 4 * width;
            int bmpSize = stride * height;

            byte[] bmp = new byte[bmpSize];
            using (ImageSurface surf =
                       new ImageSurface(bmp, Format.Argb32, width, height, stride))
            {
                using (Context ctx = new Context(surf))
                {
                    ctx.SetSourceRGB(1, 0, 0);
                    ctx.Rectangle(10, 10, 100, 100);
                    ctx.Fill();
                }
                surf.Flush();
                //surf.WriteToPng(@"c:/test.png");
            }
            //now you have bmp filled, and may pass it to your game engine as texture
        }
示例#15
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);
        }
示例#16
0
        protected unsafe override void OnMouseMove(object o, Gtk.MotionNotifyEventArgs args, Cairo.PointD point)
        {
            Document doc = PintaCore.Workspace.ActiveDocument;

            ColorBgra old_color;
            ColorBgra new_color;

            if (mouse_button == 1)
            {
                old_color = PintaCore.Palette.PrimaryColor.ToColorBgra();
                new_color = PintaCore.Palette.SecondaryColor.ToColorBgra();
            }
            else if (mouse_button == 3)
            {
                old_color = PintaCore.Palette.SecondaryColor.ToColorBgra();
                new_color = PintaCore.Palette.PrimaryColor.ToColorBgra();
            }
            else
            {
                last_point = point_empty;
                return;
            }

            int x = (int)point.X;
            int y = (int)point.Y;

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

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

            ImageSurface surf      = doc.CurrentUserLayer.Surface;
            ImageSurface tmp_layer = doc.ToolLayer.Surface;

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

            roi         = PintaCore.Workspace.ClampToImageSize(roi);
            myTolerance = (int)(Tolerance * 256);

            tmp_layer.Flush();

            ColorBgra *tmp_data_ptr  = (ColorBgra *)tmp_layer.DataPtr;
            int        tmp_width     = tmp_layer.Width;
            ColorBgra *surf_data_ptr = (ColorBgra *)surf.DataPtr;
            int        surf_width    = surf.Width;

            // The stencil lets us know if we've already checked this
            // pixel, providing a nice perf boost
            // Maybe this should be changed to a BitVector2DSurfaceAdapter?
            for (int i = roi.X; i <= roi.GetRight(); i++)
            {
                for (int j = roi.Y; j <= roi.GetBottom(); j++)
                {
                    if (stencil[i, j])
                    {
                        continue;
                    }

                    if (IsColorInTolerance(new_color, surf.GetColorBgraUnchecked(surf_data_ptr, surf_width, i, j)))
                    {
                        *tmp_layer.GetPointAddressUnchecked(tmp_data_ptr, tmp_width, i, j) = AdjustColorDifference(new_color, old_color, surf.GetColorBgraUnchecked(surf_data_ptr, surf_width, i, j));
                    }

                    stencil[i, j] = true;
                }
            }

            tmp_layer.MarkDirty();

            using (Context g = new Context(surf)) {
                g.AppendPath(doc.Selection.SelectionPath);
                g.FillRule = FillRule.EvenOdd;
                g.Clip();

                g.Antialias = UseAntialiasing ? Antialias.Subpixel : Antialias.None;

                g.MoveTo(last_point.X, last_point.Y);
                g.LineTo(x, y);

                g.LineWidth = BrushWidth;
                g.LineJoin  = LineJoin.Round;
                g.LineCap   = LineCap.Round;

                g.SetSource(tmp_layer);

                g.Stroke();
            }

            doc.Workspace.Invalidate(roi);

            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;

            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);
        }
示例#18
0
        unsafe public void Render(ImageSurface surface, Gdk.Rectangle[] rois)
        {
            byte startAlpha;
            byte endAlpha;

            if (this.alphaOnly)
            {
                ComputeAlphaOnlyValuesFromColors(this.startColor, this.endColor, out startAlpha, out endAlpha);
            }
            else
            {
                startAlpha = this.startColor.A;
                endAlpha   = this.endColor.A;
            }

            surface.Flush();

            ColorBgra *src_data_ptr = (ColorBgra *)surface.DataPtr;
            int        src_width    = surface.Width;

            for (int ri = 0; ri < rois.Length; ++ri)
            {
                Gdk.Rectangle rect = rois[ri];

                if (this.startPoint.X == this.endPoint.X && this.startPoint.Y == this.endPoint.Y)
                {
                    // Start and End point are the same ... fill with solid color.
                    for (int y = rect.Top; y <= rect.GetBottom(); ++y)
                    {
                        ColorBgra *pixelPtr = surface.GetPointAddress(rect.Left, y);

                        for (int x = rect.Left; x <= rect.GetRight(); ++x)
                        {
                            ColorBgra result;

                            if (this.alphaOnly && this.alphaBlending)
                            {
                                byte resultAlpha = (byte)Utility.FastDivideShortByByte((ushort)(pixelPtr->A * endAlpha), 255);
                                result   = *pixelPtr;
                                result.A = resultAlpha;
                            }
                            else if (this.alphaOnly && !this.alphaBlending)
                            {
                                result   = *pixelPtr;
                                result.A = endAlpha;
                            }
                            else if (!this.alphaOnly && this.alphaBlending)
                            {
                                result = this.normalBlendOp.Apply(*pixelPtr, this.endColor);
                                //if (!this.alphaOnly && !this.alphaBlending)
                            }
                            else
                            {
                                result = this.endColor;
                            }

                            *pixelPtr = result;
                            ++pixelPtr;
                        }
                    }
                }
                else
                {
                    var mainrect = rect;
                    Parallel.ForEach(Enumerable.Range(rect.Top, rect.Height),
                                     (y) => ProcessGradientLine(startAlpha, endAlpha, y, mainrect, surface, src_data_ptr, src_width));
                }
            }

            surface.MarkDirty();
            AfterRender();
        }
示例#19
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);
        }
示例#20
0
        /// <summary>
        /// The average color of the pixels in the current represenation of the item,
        /// weighted for saturation and opacity.
        /// </summary>
        /// <returns>
        /// A <see cref="Cairo.Color"/>
        /// </returns>
        public Cairo.Color AverageColor()
        {
            if (icon_buffers [0] == null)
            {
                return(new Cairo.Color(1, 1, 1, 1));
            }

            if (average_color.HasValue)
            {
                return(average_color.Value);
            }

            ImageSurface sr = new ImageSurface(Format.ARGB32, icon_buffers [0].Width, icon_buffers [0].Height);

            using (Context cr = new Context(sr)) {
                cr.Operator = Operator.Source;
                icon_buffers [0].Internal.Show(cr, 0, 0);
            }

            sr.Flush();

            byte [] data;
            try {
                data = sr.Data;
            } catch {
                return(new Cairo.Color(1, 1, 1, 1));
            }
            byte r, g, b;

            double rTotal = 0;
            double gTotal = 0;
            double bTotal = 0;

            unsafe
            {
                fixed(byte *dataSrc = data)
                {
                    byte *dataPtr = dataSrc;

                    for (int i = 0; i < data.Length - 3; i += 4)
                    {
                        b = dataPtr [0];
                        g = dataPtr [1];
                        r = dataPtr [2];

                        byte   max   = Math.Max(r, Math.Max(g, b));
                        byte   min   = Math.Min(r, Math.Min(g, b));
                        double delta = max - min;

                        double sat;
                        if (delta == 0)
                        {
                            sat = 0;
                        }
                        else
                        {
                            sat = delta / max;
                        }
                        double score = .2 + .8 * sat;

                        rTotal += r * score;
                        gTotal += g * score;
                        bTotal += b * score;

                        dataPtr += 4;
                    }
                }
            }

            double pixelCount = icon_buffers [0].Width * icon_buffers [0].Height * byte.MaxValue;

            // FIXME: once we use mono 2.6.3+ we can do sr.Dispose ()
            (sr as IDisposable).Dispose();
            sr.Destroy();

            average_color = new Cairo.Color(rTotal / pixelCount,
                                            gTotal / pixelCount,
                                            bTotal / pixelCount)
                            .SetValue(.8)
                            .MultiplySaturation(1.15);

            return(average_color.Value);
        }
示例#21
0
 public void SetDrawable(Drawable drawable)
 {
     _drawable = drawable;
     _surface.Flush();
 }
示例#22
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);
        }
示例#23
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 tmpCol     = tmp [ix, iy];
                            int       red        = tmpCol.R;
                            int       green      = tmpCol.G;
                            int       blue       = tmpCol.B;
                            int       alpha      = tmpCol.A;
                            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 = ColorBgra.FromBgra((byte)blue, (byte)green, (byte)red, (byte)alpha).ToPremultipliedAlpha();

                            *dstRowPtr = col;
                        }
                        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);
        }
示例#24
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) + 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);
        }