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.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); }