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; }
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); ColorBgra colorTopRight = src.GetColorBgraUnchecked (right, top); ColorBgra colorBottomLeft = src.GetColorBgraUnchecked (left, bottom); ColorBgra colorBottomRight = src.GetColorBgraUnchecked (right, bottom); ColorBgra c = ColorBgra.BlendColors4W16IP (colorTopLeft, 16384, colorTopRight, 16384, colorBottomLeft, 16384, colorBottomRight, 16384); return c; }
/// <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); } }
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); }
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; } } } }