예제 #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, 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);
        }
예제 #2
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());
        }
예제 #3
0
        protected override void OnMouseDown(Gtk.DrawingArea canvas, Gtk.ButtonPressEventArgs args, PointD point)
        {
            Document doc = PintaCore.Workspace.ActiveDocument;

            Point pos = new Point((int)point.X, (int)point.Y);

            // Don't do anything if we're outside the canvas
            if (pos.X < 0 || pos.X >= doc.ImageSize.Width)
            {
                return;
            }
            if (pos.Y < 0 || pos.Y >= doc.ImageSize.Height)
            {
                return;
            }

            base.OnMouseDown(canvas, args, point);

            Gdk.Region currentRegion = Gdk.Region.Rectangle(doc.GetSelectedBounds(true));

            // See if the mouse click is valid
            if (!currentRegion.PointIn(pos.X, pos.Y) && limitToSelection)
            {
                currentRegion.Dispose();
                currentRegion = null;
                return;
            }

            ImageSurface surface = doc.CurrentUserLayer.Surface;

            using (var stencil_surface = new ImageSurface(Format.Argb32, (int)surface.Width, (int)surface.Height)) {
                IBitVector2D stencilBuffer = new BitVector2DSurfaceAdapter(stencil_surface);
                int          tol           = (int)(Tolerance * Tolerance * 256);
                Rectangle    boundingBox;

                if (IsContinguousMode)
                {
                    FillStencilFromPoint(surface, stencilBuffer, pos, tol, out boundingBox, currentRegion, limitToSelection);
                }
                else
                {
                    FillStencilByColor(surface, stencilBuffer, surface.GetColorBgraUnchecked(pos.X, pos.Y), tol, out boundingBox, currentRegion, LimitToSelection);
                }

                OnFillRegionComputed(stencilBuffer);

                // If a derived tool is only going to use the stencil,
                // don't waste time building the polygon set
                if (CalculatePolygonSet)
                {
                    Point[][] polygonSet = stencilBuffer.CreatePolygonSet(boundingBox, 0, 0);
                    OnFillRegionComputed(polygonSet);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Gets the final pixel color for the given point, taking layers, opacity, and blend modes into account.
        /// </summary>
        public ColorBgra GetComputedPixel(int x, int y)
        {
            using (var dst = new ImageSurface(Format.Argb32, 1, 1)) {
                using (var g = new Context(dst)) {
                    foreach (var layer in GetLayersToPaint())
                    {
                        var color = layer.Surface.GetColorBgraUnchecked(x, y).ToStraightAlpha().ToCairoColor();

                        g.SetBlendMode(layer.BlendMode);
                        g.SetSourceColor(color);

                        g.Rectangle(dst.GetBounds().ToCairoRectangle());
                        g.PaintWithAlpha(layer.Opacity);
                    }
                }

                return(dst.GetColorBgraUnchecked(0, 0));
            }
        }
예제 #5
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);
        }
예제 #6
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);
        }
예제 #7
0
        public unsafe static void FillStencilFromPoint(ImageSurface surface, IBitVector2D stencil, Point start, int tolerance,
                                                       out Rectangle boundingBox, Gdk.Region limitRegion, bool limitToSelection)
        {
            ColorBgra cmp    = surface.GetColorBgraUnchecked(start.X, start.Y);
            int       top    = int.MaxValue;
            int       bottom = int.MinValue;
            int       left   = int.MaxValue;
            int       right  = int.MinValue;

            Gdk.Rectangle[] scans;

            stencil.Clear(false);

            if (limitToSelection)
            {
                using (Gdk.Region excluded = Gdk.Region.Rectangle(new Gdk.Rectangle(0, 0, stencil.Width, stencil.Height))) {
                    excluded.Xor(limitRegion);
                    scans = excluded.GetRectangles();
                }
            }
            else
            {
                scans = new Gdk.Rectangle[0];
            }

            foreach (Gdk.Rectangle rect in scans)
            {
                stencil.Set(rect, true);
            }

            Queue <Point> queue = new Queue <Point> (16);

            queue.Enqueue(start);

            while (queue.Count > 0)
            {
                Point pt = queue.Dequeue();

                ColorBgra *rowPtr     = surface.GetRowAddressUnchecked(pt.Y);
                int        localLeft  = pt.X - 1;
                int        localRight = pt.X;

                while (localLeft >= 0 &&
                       !stencil.GetUnchecked(localLeft, pt.Y) &&
                       CheckColor(cmp, rowPtr[localLeft], tolerance))
                {
                    stencil.SetUnchecked(localLeft, pt.Y, true);
                    --localLeft;
                }

                int surfaceWidth = surface.Width;
                while (localRight < surfaceWidth &&
                       !stencil.GetUnchecked(localRight, pt.Y) &&
                       CheckColor(cmp, rowPtr[localRight], tolerance))
                {
                    stencil.SetUnchecked(localRight, pt.Y, true);
                    ++localRight;
                }

                ++localLeft;
                --localRight;

                Action <int> checkRow = (row) =>
                {
                    int        sleft       = localLeft;
                    int        sright      = localLeft;
                    ColorBgra *otherRowPtr = surface.GetRowAddressUnchecked(row);

                    for (int sx = localLeft; sx <= localRight; ++sx)
                    {
                        if (!stencil.GetUnchecked(sx, row) &&
                            CheckColor(cmp, otherRowPtr[sx], tolerance))
                        {
                            ++sright;
                        }
                        else
                        {
                            if (sright - sleft > 0)
                            {
                                queue.Enqueue(new Point(sleft, row));
                            }

                            ++sright;
                            sleft = sright;
                        }
                    }

                    if (sright - sleft > 0)
                    {
                        queue.Enqueue(new Point(sleft, row));
                    }
                };

                if (pt.Y > 0)
                {
                    checkRow(pt.Y - 1);
                }

                if (pt.Y < surface.Height - 1)
                {
                    checkRow(pt.Y + 1);
                }

                if (localLeft < left)
                {
                    left = localLeft;
                }

                if (localRight > right)
                {
                    right = localRight;
                }

                if (pt.Y < top)
                {
                    top = pt.Y;
                }

                if (pt.Y > bottom)
                {
                    bottom = pt.Y;
                }
            }

            foreach (Gdk.Rectangle rect in scans)
            {
                stencil.Set(rect, false);
            }

            boundingBox = new Rectangle(left, top, right - left + 1, bottom - top + 1);
        }
예제 #8
0
파일: WarpEffect.cs 프로젝트: ywscr/Pinta
        public unsafe override void Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois)
        {
            var selection = PintaCore.LivePreview.RenderBounds;

            this.defaultRadius  = Math.Min(selection.Width, selection.Height) * 0.5;
            this.defaultRadius2 = this.defaultRadius * this.defaultRadius;

            var x_center_offset = selection.Left + (selection.Width * (1.0 + Data.CenterOffset.X) * 0.5);
            var y_center_offset = selection.Top + (selection.Height * (1.0 + Data.CenterOffset.Y) * 0.5);

            ColorBgra colPrimary     = PintaCore.Palette.PrimaryColor.ToColorBgra();
            ColorBgra colSecondary   = PintaCore.Palette.SecondaryColor.ToColorBgra();
            ColorBgra colTransparent = ColorBgra.Transparent;

            int aaSampleCount = Data.Quality * Data.Quality;

            Cairo.PointD *aaPoints = stackalloc Cairo.PointD[aaSampleCount];
            Utility.GetRgssOffsets(aaPoints, aaSampleCount, Data.Quality);
            ColorBgra *samples = stackalloc ColorBgra[aaSampleCount];

            TransformData td;

            foreach (Gdk.Rectangle rect in rois)
            {
                for (int y = rect.Top; y <= rect.GetBottom(); y++)
                {
                    ColorBgra *dstPtr = dst.GetPointAddressUnchecked(rect.Left, y);

                    double relativeY = y - y_center_offset;

                    for (int x = rect.Left; x <= rect.GetRight(); x++)
                    {
                        double relativeX = x - x_center_offset;

                        int sampleCount = 0;

                        for (int p = 0; p < aaSampleCount; ++p)
                        {
                            td.X = relativeX + aaPoints[p].X;
                            td.Y = relativeY - aaPoints[p].Y;

                            InverseTransform(ref td);

                            float sampleX = (float)(td.X + x_center_offset);
                            float sampleY = (float)(td.Y + y_center_offset);

                            ColorBgra sample = colPrimary;

                            if (IsOnSurface(src, sampleX, sampleY))
                            {
                                sample = src.GetBilinearSample(sampleX, sampleY);
                            }
                            else
                            {
                                switch (Data.EdgeBehavior)
                                {
                                case WarpEdgeBehavior.Clamp:
                                    sample = src.GetBilinearSampleClamped(sampleX, sampleY);
                                    break;

                                case WarpEdgeBehavior.Wrap:
                                    sample = src.GetBilinearSampleWrapped(sampleX, sampleY);
                                    break;

                                case WarpEdgeBehavior.Reflect:
                                    sample = src.GetBilinearSampleClamped(ReflectCoord(sampleX, src.Width), ReflectCoord(sampleY, src.Height));

                                    break;

                                case WarpEdgeBehavior.Primary:
                                    sample = colPrimary;
                                    break;

                                case WarpEdgeBehavior.Secondary:
                                    sample = colSecondary;
                                    break;

                                case WarpEdgeBehavior.Transparent:
                                    sample = colTransparent;
                                    break;

                                case WarpEdgeBehavior.Original:
                                    sample = src.GetColorBgraUnchecked(x, y);
                                    break;

                                default:

                                    break;
                                }
                            }

                            samples[sampleCount] = sample;
                            ++sampleCount;
                        }

                        *dstPtr = ColorBgra.Blend(samples, sampleCount);
                        ++dstPtr;
                    }
                }
            }
        }