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; ImageSurface 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.GetColorBgra(pos.X, pos.Y), tol, out boundingBox, currentRegion, LimitToSelection); } stencil = stencilBuffer; 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); } }
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(); }
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 (); }
public static unsafe void FillStencilByColor(ImageSurface surface, IBitVector2D stencil, ColorBgra cmp, int tolerance, out Rectangle boundingBox) { int top = int.MaxValue; int bottom = int.MinValue; int left = int.MaxValue; int right = int.MinValue; stencil.Clear (false); for (int y = 0; y < surface.Height; ++y) { bool foundPixelInRow = false; ColorBgra* ptr = surface.GetRowAddressUnchecked (y); for (int x = 0; x < surface.Width; ++x) { if (CheckColor (cmp, *ptr, tolerance)) { stencil.SetUnchecked (x, y, true); if (x < left) { left = x; } if (x > right) { right = x; } foundPixelInRow = true; } ++ptr; } if (foundPixelInRow) { if (y < top) { top = y; } if (y >= bottom) { bottom = y; } } } boundingBox = new Rectangle (left, top, right + 1, bottom + 1); }
public unsafe static void FillStencilFromPoint(Surface surface, IBitVector2D stencil, Point start, int tolerance, out Rectangle boundingBox, PdnRegion limitRegion, bool limitToSelection) { ColorBgra cmp = surface[start]; int top = int.MaxValue; int bottom = int.MinValue; int left = int.MaxValue; int right = int.MinValue; Rectangle[] scans; stencil.Clear(false); if (limitToSelection) { using (PdnRegion excluded = new PdnRegion(new Rectangle(0, 0, stencil.Width, stencil.Height))) { excluded.Xor(limitRegion); scans = excluded.GetRegionScansReadOnlyInt(); } } else { scans = new Rectangle[0]; } foreach (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; } while (localRight < surface.Width && !stencil.GetUnchecked(localRight, pt.Y) && CheckColor(cmp, rowPtr[localRight], tolerance)) { stencil.SetUnchecked(localRight, pt.Y, true); ++localRight; } ++localLeft; --localRight; if (pt.Y > 0) { int sleft = localLeft; int sright = localLeft; ColorBgra *rowPtrUp = surface.GetRowAddressUnchecked(pt.Y - 1); for (int sx = localLeft; sx <= localRight; ++sx) { if (!stencil.GetUnchecked(sx, pt.Y - 1) && CheckColor(cmp, rowPtrUp[sx], tolerance)) { ++sright; } else { if (sright - sleft > 0) { queue.Enqueue(new Point(sleft, pt.Y - 1)); } ++sright; sleft = sright; } } if (sright - sleft > 0) { queue.Enqueue(new Point(sleft, pt.Y - 1)); } } if (pt.Y < surface.Height - 1) { int sleft = localLeft; int sright = localLeft; ColorBgra *rowPtrDown = surface.GetRowAddressUnchecked(pt.Y + 1); for (int sx = localLeft; sx <= localRight; ++sx) { if (!stencil.GetUnchecked(sx, pt.Y + 1) && CheckColor(cmp, rowPtrDown[sx], tolerance)) { ++sright; } else { if (sright - sleft > 0) { queue.Enqueue(new Point(sleft, pt.Y + 1)); } ++sright; sleft = sright; } } if (sright - sleft > 0) { queue.Enqueue(new Point(sleft, 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 (Rectangle rect in scans) { stencil.Set(rect, false); } boundingBox = Rectangle.FromLTRB(left, top, right + 1, bottom + 1); }
public static unsafe void FillStencilFromPoint(Surface surface, IBitVector2D stencil, Point start, int tolerance, out Rectangle boundingBox, PdnRegion limitRegion, bool limitToSelection) { ColorBgra cmp = surface[start]; int top = int.MaxValue; int bottom = int.MinValue; int left = int.MaxValue; int right = int.MinValue; Rectangle[] scans; stencil.Clear(false); if (limitToSelection) { using (PdnRegion excluded = new PdnRegion(new Rectangle(0, 0, stencil.Width, stencil.Height))) { excluded.Xor(limitRegion); scans = excluded.GetRegionScansReadOnlyInt(); } } else { scans = new Rectangle[0]; } foreach (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; } while (localRight < surface.Width && !stencil.GetUnchecked(localRight, pt.Y) && CheckColor(cmp, rowPtr[localRight], tolerance)) { stencil.SetUnchecked(localRight, pt.Y, true); ++localRight; } ++localLeft; --localRight; if (pt.Y > 0) { int sleft = localLeft; int sright = localLeft; ColorBgra* rowPtrUp = surface.GetRowAddressUnchecked(pt.Y - 1); for (int sx = localLeft; sx <= localRight; ++sx) { if (!stencil.GetUnchecked(sx, pt.Y - 1) && CheckColor(cmp, rowPtrUp[sx], tolerance)) { ++sright; } else { if (sright - sleft > 0) { queue.Enqueue(new Point(sleft, pt.Y - 1)); } ++sright; sleft = sright; } } if (sright - sleft > 0) { queue.Enqueue(new Point(sleft, pt.Y - 1)); } } if (pt.Y < surface.Height - 1) { int sleft = localLeft; int sright = localLeft; ColorBgra* rowPtrDown = surface.GetRowAddressUnchecked(pt.Y + 1); for (int sx = localLeft; sx <= localRight; ++sx) { if (!stencil.GetUnchecked(sx, pt.Y + 1) && CheckColor(cmp, rowPtrDown[sx], tolerance)) { ++sright; } else { if (sright - sleft > 0) { queue.Enqueue(new Point(sleft, pt.Y + 1)); } ++sright; sleft = sright; } } if (sright - sleft > 0) { queue.Enqueue(new Point(sleft, 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 (Rectangle rect in scans) { stencil.Set(rect, false); } boundingBox = Rectangle.FromLTRB(left, top, right + 1, bottom + 1); }
/// <summary> /// Creates a graphics path from the given stencil buffer. It should be filled with 'true' values /// to indicate the areas that should be outlined. /// </summary> /// <param name="stencil">The stencil buffer to read from. NOTE: The contents of this will be destroyed when this method returns.</param> /// <param name="bounds">The bounding box within the stencil buffer to limit discovery to.</param> /// <returns>A PdnGraphicsPath with traces that outline the various areas from the given stencil buffer.</returns> public unsafe static PdnGraphicsPath PathFromStencil(IBitVector2D stencil, Rectangle bounds) { if (stencil.IsEmpty) { return(new PdnGraphicsPath()); } PdnGraphicsPath ret = new PdnGraphicsPath(); Point start = bounds.Location; Vector <Point> pts = new Vector <Point>(); int count = 0; // find all islands while (true) { bool startFound = false; while (true) { if (stencil[start]) { startFound = true; break; } ++start.X; if (start.X >= bounds.Right) { ++start.Y; start.X = bounds.Left; if (start.Y >= bounds.Bottom) { break; } } } if (!startFound) { break; } pts.Clear(); Point last = new Point(start.X, start.Y + 1); Point curr = new Point(start.X, start.Y); Point next = curr; Point left = Point.Empty; Point right = Point.Empty; // trace island outline while (true) { left.X = ((curr.X - last.X) + (curr.Y - last.Y) + 2) / 2 + curr.X - 1; left.Y = ((curr.Y - last.Y) - (curr.X - last.X) + 2) / 2 + curr.Y - 1; right.X = ((curr.X - last.X) - (curr.Y - last.Y) + 2) / 2 + curr.X - 1; right.Y = ((curr.Y - last.Y) + (curr.X - last.X) + 2) / 2 + curr.Y - 1; if (bounds.Contains(left) && stencil[left]) { // go left next.X += curr.Y - last.Y; next.Y -= curr.X - last.X; } else if (bounds.Contains(right) && stencil[right]) { // go straight next.X += curr.X - last.X; next.Y += curr.Y - last.Y; } else { // turn right next.X -= curr.Y - last.Y; next.Y += curr.X - last.X; } if (Math.Sign(next.X - curr.X) != Math.Sign(curr.X - last.X) || Math.Sign(next.Y - curr.Y) != Math.Sign(curr.Y - last.Y)) { pts.Add(curr); ++count; } last = curr; curr = next; if (next.X == start.X && next.Y == start.Y) { break; } } Point[] points = pts.ToArray(); Scanline[] scans = Utility.GetScans(points); foreach (Scanline scan in scans) { stencil.Invert(scan); } ret.AddLines(points); ret.CloseFigure(); } return(ret); }
protected virtual void OnFillRegionComputed(IBitVector2D stencil) { }
/// <summary> /// Creates a graphics path from the given stencil buffer. It should be filled with 'true' values /// to indicate the areas that should be outlined. /// </summary> /// <param name="stencil">The stencil buffer to read from. NOTE: The contents of this will be destroyed when this method returns.</param> /// <param name="bounds">The bounding box within the stencil buffer to limit discovery to.</param> /// <returns>A PdnGraphicsPath with traces that outline the various areas from the given stencil buffer.</returns> public unsafe static PdnGraphicsPath PathFromStencil(IBitVector2D stencil, Rectangle bounds) { if (stencil.IsEmpty) { return new PdnGraphicsPath(); } PdnGraphicsPath ret = new PdnGraphicsPath(); Point start = bounds.Location; Vector<Point> pts = new Vector<Point>(); int count = 0; // find all islands while (true) { bool startFound = false; while (true) { if (stencil[start]) { startFound = true; break; } ++start.X; if (start.X >= bounds.Right) { ++start.Y; start.X = bounds.Left; if (start.Y >= bounds.Bottom) { break; } } } if (!startFound) { break; } pts.Clear(); Point last = new Point(start.X, start.Y + 1); Point curr = new Point(start.X, start.Y); Point next = curr; Point left = Point.Empty; Point right = Point.Empty; // trace island outline while (true) { left.X = ((curr.X - last.X) + (curr.Y - last.Y) + 2) / 2 + curr.X - 1; left.Y = ((curr.Y - last.Y) - (curr.X - last.X) + 2) / 2 + curr.Y - 1; right.X = ((curr.X - last.X) - (curr.Y - last.Y) + 2) / 2 + curr.X - 1; right.Y = ((curr.Y - last.Y) + (curr.X - last.X) + 2) / 2 + curr.Y - 1; if (bounds.Contains(left) && stencil[left]) { // go left next.X += curr.Y - last.Y; next.Y -= curr.X - last.X; } else if (bounds.Contains(right) && stencil[right]) { // go straight next.X += curr.X - last.X; next.Y += curr.Y - last.Y; } else { // turn right next.X -= curr.Y - last.Y; next.Y += curr.X - last.X; } if (Math.Sign(next.X - curr.X) != Math.Sign(curr.X - last.X) || Math.Sign(next.Y - curr.Y) != Math.Sign(curr.Y - last.Y)) { pts.Add(curr); ++count; } last = curr; curr = next; if (next.X == start.X && next.Y == start.Y) { break; } } Point[] points = pts.ToArray(); Scanline[] scans = Utility.GetScans(points); foreach (Scanline scan in scans) { stencil.Invert(scan); } ret.AddLines(points); ret.CloseFigure(); } return ret; }
public unsafe static Point[][] PolygonSetFromStencil(IBitVector2D stencil, Rectangle bounds, int translateX, int translateY) { List<Point[]> polygons = new List<Point[]>(); if (!stencil.IsEmpty) { Point start = bounds.Location; List<Point> pts = new List<Point>(); int count = 0; // find all islands while (true) { bool startFound = false; while (true) { if (stencil[start]) { startFound = true; break; } ++start.X; if (start.X >= bounds.Right) { ++start.Y; start.X = bounds.Left; if (start.Y >= bounds.Bottom) { break; } } } if (!startFound) { break; } pts.Clear(); Point last = new Point(start.X, start.Y + 1); Point curr = new Point(start.X, start.Y); Point next = curr; Point left = Point.Empty; Point right = Point.Empty; // trace island outline while (true) { left.X = ((curr.X - last.X) + (curr.Y - last.Y) + 2) / 2 + curr.X - 1; left.Y = ((curr.Y - last.Y) - (curr.X - last.X) + 2) / 2 + curr.Y - 1; right.X = ((curr.X - last.X) - (curr.Y - last.Y) + 2) / 2 + curr.X - 1; right.Y = ((curr.Y - last.Y) + (curr.X - last.X) + 2) / 2 + curr.Y - 1; if (bounds.Contains(left) && stencil[left]) { // go left next.X += curr.Y - last.Y; next.Y -= curr.X - last.X; } else if (bounds.Contains(right) && stencil[right]) { // go straight next.X += curr.X - last.X; next.Y += curr.Y - last.Y; } else { // turn right next.X -= curr.Y - last.Y; next.Y += curr.X - last.X; } if (Math.Sign(next.X - curr.X) != Math.Sign(curr.X - last.X) || Math.Sign(next.Y - curr.Y) != Math.Sign(curr.Y - last.Y)) { pts.Add(curr); ++count; } last = curr; curr = next; if (next.X == start.X && next.Y == start.Y) { break; } } Point[] points = pts.ToArray(); Scanline[] scans = Utility.GetScans(points); foreach (Scanline scan in scans) { stencil.Invert(scan); } Utility.TranslatePointsInPlace(points, translateX, translateY); polygons.Add(points); } } Point[][] returnVal = polygons.ToArray(); return returnVal; }
public unsafe static void FillStencilByColor (ImageSurface surface, IBitVector2D stencil, ColorBgra cmp, int tolerance, out Rectangle boundingBox, Gdk.Region limitRegion, bool limitToSelection) { 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); Parallel.For(0, surface.Height, y => { bool foundPixelInRow = false; ColorBgra* ptr = surface.GetRowAddressUnchecked(y); int surfaceWidth = surface.Width; for (int x = 0; x < surfaceWidth; ++x) { if (CheckColor(cmp, *ptr, tolerance)) { stencil.SetUnchecked(x, y, true); if (x < left) { left = x; } if (x > right) { right = x; } foundPixelInRow = true; } ++ptr; } if (foundPixelInRow) { if (y < top) { top = y; } if (y >= bottom) { bottom = y; } } }); foreach (Gdk.Rectangle rect in scans) stencil.Set (rect, false); boundingBox = new Rectangle (left, top, right - left + 1, bottom - top + 1); }
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); }
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; ImageSurface 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.GetColorBgra (pos.X, pos.Y), tol, out boundingBox, currentRegion, LimitToSelection); stencil = stencilBuffer; 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); } }
public unsafe static void FillStencilByColor(Surface surface, IBitVector2D stencil, ColorBgra cmp, int tolerance, out Rectangle boundingBox, PdnRegion limitRegion, bool limitToSelection) { int top = int.MaxValue; int bottom = int.MinValue; int left = int.MaxValue; int right = int.MinValue; Rectangle[] scans; stencil.Clear(false); if (limitToSelection) { using (PdnRegion excluded = new PdnRegion(new Rectangle(0, 0, stencil.Width, stencil.Height))) { excluded.Xor(limitRegion); scans = excluded.GetRegionScansReadOnlyInt(); } } else { scans = new Rectangle[0]; } foreach (Rectangle rect in scans) { stencil.Set(rect, true); } for (int y = 0; y < surface.Height; ++y) { bool foundPixelInRow = false; ColorBgra *ptr = surface.GetRowAddressUnchecked(y); for (int x = 0; x < surface.Width; ++x) { if (CheckColor(cmp, *ptr, tolerance)) { stencil.SetUnchecked(x, y, true); if (x < left) { left = x; } if (x > right) { right = x; } foundPixelInRow = true; } ++ptr; } if (foundPixelInRow) { if (y < top) { top = y; } if (y >= bottom) { bottom = y; } } } foreach (Rectangle rect in scans) { stencil.Set(rect, false); } boundingBox = Rectangle.FromLTRB(left, top, right + 1, bottom + 1); }
public unsafe static void FillStencilFromPoint(ImageSurface surface, IBitVector2D stencil, Point start, int tolerance, out Rectangle boundingBox, Gdk.Region limitRegion, bool limitToSelection) { ColorBgra cmp = surface.GetColorBgra(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); }
public unsafe static void FillStencilByColor(ImageSurface surface, IBitVector2D stencil, ColorBgra cmp, int tolerance, out Rectangle boundingBox, Gdk.Region limitRegion, bool limitToSelection) { 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); } Parallel.For(0, surface.Height, y => { bool foundPixelInRow = false; ColorBgra *ptr = surface.GetRowAddressUnchecked(y); int surfaceWidth = surface.Width; for (int x = 0; x < surfaceWidth; ++x) { if (CheckColor(cmp, *ptr, tolerance)) { stencil.SetUnchecked(x, y, true); if (x < left) { left = x; } if (x > right) { right = x; } foundPixelInRow = true; } ++ptr; } if (foundPixelInRow) { if (y < top) { top = y; } if (y >= bottom) { bottom = y; } } }); foreach (Gdk.Rectangle rect in scans) { stencil.Set(rect, false); } boundingBox = new Rectangle(left, top, right - left + 1, bottom - top + 1); }
public unsafe static Point[][] PolygonSetFromStencil(IBitVector2D stencil, Rectangle bounds, int translateX, int translateY) { List <Point[]> polygons = new List <Point[]>(); if (!stencil.IsEmpty) { Point start = bounds.Location; List <Point> pts = new List <Point>(); int count = 0; // find all islands while (true) { bool startFound = false; while (true) { if (stencil[start]) { startFound = true; break; } ++start.X; if (start.X >= bounds.Right) { ++start.Y; start.X = bounds.Left; if (start.Y >= bounds.Bottom) { break; } } } if (!startFound) { break; } pts.Clear(); Point last = new Point(start.X, start.Y + 1); Point curr = new Point(start.X, start.Y); Point next = curr; Point left = Point.Empty; Point right = Point.Empty; // trace island outline while (true) { left.X = ((curr.X - last.X) + (curr.Y - last.Y) + 2) / 2 + curr.X - 1; left.Y = ((curr.Y - last.Y) - (curr.X - last.X) + 2) / 2 + curr.Y - 1; right.X = ((curr.X - last.X) - (curr.Y - last.Y) + 2) / 2 + curr.X - 1; right.Y = ((curr.Y - last.Y) + (curr.X - last.X) + 2) / 2 + curr.Y - 1; if (bounds.Contains(left) && stencil[left]) { // go left next.X += curr.Y - last.Y; next.Y -= curr.X - last.X; } else if (bounds.Contains(right) && stencil[right]) { // go straight next.X += curr.X - last.X; next.Y += curr.Y - last.Y; } else { // turn right next.X -= curr.Y - last.Y; next.Y += curr.X - last.X; } if (Math.Sign(next.X - curr.X) != Math.Sign(curr.X - last.X) || Math.Sign(next.Y - curr.Y) != Math.Sign(curr.Y - last.Y)) { pts.Add(curr); ++count; } last = curr; curr = next; if (next.X == start.X && next.Y == start.Y) { break; } } Point[] points = pts.ToArray(); Scanline[] scans = Utility.GetScans(points); foreach (Scanline scan in scans) { stencil.Invert(scan); } Utility.TranslatePointsInPlace(points, translateX, translateY); polygons.Add(points); } } Point[][] returnVal = polygons.ToArray(); return(returnVal); }
public static unsafe void FillStencilFromPoint(ImageSurface surface, IBitVector2D stencil, Point start, int tolerance, out Rectangle boundingBox) { ColorBgra cmp = surface.GetColorBgra (start.X, start.Y); int top = int.MaxValue; int bottom = int.MinValue; int left = int.MaxValue; int right = int.MinValue; stencil.Clear (false); 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; } while (localRight < surface.Width && !stencil.GetUnchecked (localRight, pt.Y) && CheckColor (cmp, rowPtr[localRight], tolerance)) { stencil.SetUnchecked (localRight, pt.Y, true); ++localRight; } ++localLeft; --localRight; if (pt.Y > 0) { int sleft = localLeft; int sright = localLeft; ColorBgra* rowPtrUp = surface.GetRowAddressUnchecked (pt.Y - 1); for (int sx = localLeft; sx <= localRight; ++sx) { if (!stencil.GetUnchecked (sx, pt.Y - 1) && CheckColor (cmp, rowPtrUp[sx], tolerance)) { ++sright; } else { if (sright - sleft > 0) { queue.Enqueue (new Point (sleft, pt.Y - 1)); } ++sright; sleft = sright; } } if (sright - sleft > 0) { queue.Enqueue (new Point (sleft, pt.Y - 1)); } } if (pt.Y < surface.Height - 1) { int sleft = localLeft; int sright = localLeft; ColorBgra* rowPtrDown = surface.GetRowAddressUnchecked (pt.Y + 1); for (int sx = localLeft; sx <= localRight; ++sx) { if (!stencil.GetUnchecked (sx, pt.Y + 1) && CheckColor (cmp, rowPtrDown[sx], tolerance)) { ++sright; } else { if (sright - sleft > 0) { queue.Enqueue (new Point (sleft, pt.Y + 1)); } ++sright; sleft = sright; } } if (sright - sleft > 0) { queue.Enqueue (new Point (sleft, 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; } } boundingBox = new Rectangle (left, top, right + 1, bottom + 1); }
protected override void OnMouseDown(Gtk.DrawingArea canvas, Gtk.ButtonPressEventArgs args, PointD point) { 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 >= PintaCore.Workspace.ImageSize.Width) return; if (pos.Y < 0 || pos.Y >= PintaCore.Workspace.ImageSize.Height) return; base.OnMouseDown (canvas, args, point); Gdk.Region currentRegion = Gdk.Region.Rectangle(PintaCore.Layers.SelectionPath.GetBounds()); // See if the mouse click is valid if (!currentRegion.PointIn (pos.X, pos.Y) && limitToSelection) { currentRegion.Dispose (); currentRegion = null; return; } ImageSurface surface = PintaCore.Layers.CurrentLayer.Surface; ImageSurface 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; surface.Flush (); if (IsContinguousMode) FillStencilFromPoint (surface, stencilBuffer, pos, tol, out boundingBox, currentRegion, limitToSelection); else FillStencilByColor (surface, stencilBuffer, surface.GetColorBgra (pos.X, pos.Y), tol, out boundingBox, currentRegion, LimitToSelection); surface.MarkDirty (); stencil = stencilBuffer; Point[][] polygonSet = stencilBuffer.CreatePolygonSet (boundingBox, 0, 0); OnFillRegionComputed (polygonSet); }
protected override void OnMouseDown(Gtk.DrawingArea canvas, Gtk.ButtonPressEventArgs args, PointD point) { 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 >= PintaCore.Workspace.ImageSize.X) return; if (pos.Y < 0 || pos.Y >= PintaCore.Workspace.ImageSize.Y) return; base.OnMouseDown (canvas, args, point); ImageSurface surface = PintaCore.Layers.CurrentLayer.Surface; ImageSurface 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); else FillStencilByColor (surface, stencilBuffer, surface.GetColorBgra (pos.X, pos.Y), tol, out boundingBox); stencil = stencilBuffer; OnFillRegionComputed (null); }
public static unsafe void FillStencilByColor(Surface surface, IBitVector2D stencil, ColorBgra cmp, int tolerance, out Rectangle boundingBox, PdnRegion limitRegion, bool limitToSelection) { int top = int.MaxValue; int bottom = int.MinValue; int left = int.MaxValue; int right = int.MinValue; Rectangle[] scans; stencil.Clear(false); if (limitToSelection) { using (PdnRegion excluded = new PdnRegion(new Rectangle(0, 0, stencil.Width, stencil.Height))) { excluded.Xor(limitRegion); scans = excluded.GetRegionScansReadOnlyInt(); } } else { scans = new Rectangle[0]; } foreach (Rectangle rect in scans) { stencil.Set(rect, true); } for (int y = 0; y < surface.Height; ++y) { bool foundPixelInRow = false; ColorBgra *ptr = surface.GetRowAddressUnchecked(y); for (int x = 0; x < surface.Width; ++x) { if (CheckColor(cmp, *ptr, tolerance)) { stencil.SetUnchecked(x, y, true); if (x < left) { left = x; } if (x > right) { right = x; } foundPixelInRow = true; } ++ptr; } if (foundPixelInRow) { if (y < top) { top = y; } if (y >= bottom) { bottom = y; } } } foreach (Rectangle rect in scans) { stencil.Set(rect, false); } boundingBox = Rectangle.FromLTRB(left, top, right + 1, bottom + 1); }
/// <summary> /// Creates a graphics path from the given stencil buffer. It should be filled with 'true' values /// to indicate the areas that should be outlined. /// </summary> /// <param name="stencil">The stencil buffer to read from. NOTE: The contents of this will be destroyed when this method returns.</param> /// <param name="bounds">The bounding box within the stencil buffer to limit discovery to.</param> /// <returns>A PdnGraphicsPath with traces that outline the various areas from the given stencil buffer.</returns> public unsafe static PdnGraphicsPath PathFromStencil(IBitVector2D stencil, Rectangle bounds) { throw new StillNotPortedException(); //if (stencil.IsEmpty) //{ // return new PdnGraphicsPath(); //} //PdnGraphicsPath ret = new PdnGraphicsPath(); //Point start = bounds.Location; //Vector<Point> pts = new Vector<Point>(); //int count = 0; //// find all islands //while (true) //{ // bool startFound = false; // while (true) // { // if (stencil[start]) // { // startFound = true; // break; // } // ++start.X; // if (start.X >= bounds.Right) // { // ++start.Y; // start.X = bounds.Left; // if (start.Y >= bounds.Bottom) // { // break; // } // } // } // if (!startFound) // { // break; // } // pts.Clear(); // Point last = new Point(start.X, start.Y + 1); // Point curr = new Point(start.X, start.Y); // Point next = curr; // Point left = Point.Empty; // Point right = Point.Empty; // // trace island outline // while (true) // { // left.X = ((curr.X - last.X) + (curr.Y - last.Y) + 2) / 2 + curr.X - 1; // left.Y = ((curr.Y - last.Y) - (curr.X - last.X) + 2) / 2 + curr.Y - 1; // right.X = ((curr.X - last.X) - (curr.Y - last.Y) + 2) / 2 + curr.X - 1; // right.Y = ((curr.Y - last.Y) + (curr.X - last.X) + 2) / 2 + curr.Y - 1; // if (bounds.Contains(left) && stencil[left]) // { // // go left // next.X += curr.Y - last.Y; // next.Y -= curr.X - last.X; // } // else if (bounds.Contains(right) && stencil[right]) // { // // go straight // next.X += curr.X - last.X; // next.Y += curr.Y - last.Y; // } // else // { // // turn right // next.X -= curr.Y - last.Y; // next.Y += curr.X - last.X; // } // if (Math.Sign(next.X - curr.X) != Math.Sign(curr.X - last.X) || // Math.Sign(next.Y - curr.Y) != Math.Sign(curr.Y - last.Y)) // { // pts.Add(curr); // ++count; // } // last = curr; // curr = next; // if (next.X == start.X && next.Y == start.Y) // { // break; // } // } // Point[] points = pts.ToArray(); // Scanline[] scans = PixelUtils.GetScans(points); // foreach (Scanline scan in scans) // { // stencil.Invert(scan); // } // ret.AddLines(points); // ret.CloseFigure(); //} //return ret; }