public void Clear(bool newValue) { unsafe { uint val = newValue ? 0xffffffff : 0; for (int y = 0; y < Height; ++y) { ColorBgra *row = surface.GetRowAddressUnchecked(src_data_ptr, src_width, y); int w = (this.Width + 31) / 32; while (w > 0) { row->Bgra = val; ++row; --w; } } } }
public unsafe override void Render(ImageSurface src, ImageSurface dest, Gdk.Rectangle[] rois) { // Glow backgound glowEffect.Data.Radius = 6; glowEffect.Data.Brightness = -(Data.Coloring - 50) * 2; glowEffect.Data.Contrast = -(Data.Coloring - 50) * 2; this.glowEffect.Render(src, dest, rois); // Create black outlines by finding the edges of objects foreach (Gdk.Rectangle roi in rois) { for (int y = roi.Top; y < roi.Bottom; ++y) { int top = y - radius; int bottom = y + radius + 1; if (top < 0) { top = 0; } if (bottom > dest.Height) { bottom = dest.Height; } ColorBgra *srcPtr = src.GetPointAddress(roi.X, y); ColorBgra *dstPtr = dest.GetPointAddress(roi.X, y); for (int x = roi.Left; x < roi.Right; ++x) { int left = x - radius; int right = x + radius + 1; if (left < 0) { left = 0; } if (right > dest.Width) { right = dest.Width; } int r = 0; int g = 0; int b = 0; int src_width = src.Width; ColorBgra *src_dataptr = (ColorBgra *)src.DataPtr; for (int v = top; v < bottom; v++) { ColorBgra *pRow = src.GetRowAddressUnchecked(src_dataptr, src_width, v); int j = v - y + radius; for (int u = left; u < right; u++) { int i1 = u - x + radius; int w = conv[j][i1]; ColorBgra *pRef = pRow + u; r += pRef->R * w; g += pRef->G * w; b += pRef->B * w; } } ColorBgra topLayer = ColorBgra.FromBgr( Utility.ClampToByte(b), Utility.ClampToByte(g), Utility.ClampToByte(r)); // Desaturate topLayer = this.desaturateOp.Apply(topLayer); // Adjust Brightness and Contrast if (topLayer.R > (Data.InkOutline * 255 / 100)) { topLayer = ColorBgra.FromBgra(255, 255, 255, topLayer.A); } else { topLayer = ColorBgra.FromBgra(0, 0, 0, topLayer.A); } // Change Blend Mode to Darken ColorBgra myPixel = this.darkenOp.Apply(topLayer, *dstPtr); * dstPtr = myPixel; ++srcPtr; ++dstPtr; } } } }
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); }
protected unsafe void eraseSmooth(ImageSurface surf, Context g, PointD start, PointD end) { int rad = (int)(BrushWidth / 2.0) + 1; //Premultiply with alpha value byte bk_col_a = (byte)(PintaCore.Palette.SecondaryColor.A * 255.0); byte bk_col_r = (byte)(PintaCore.Palette.SecondaryColor.R * bk_col_a); byte bk_col_g = (byte)(PintaCore.Palette.SecondaryColor.G * bk_col_a); byte bk_col_b = (byte)(PintaCore.Palette.SecondaryColor.B * bk_col_a); int num_steps = (int)start.Distance(end) / rad + 1; //Initialize lookup table when first used (to prevent slower startup of the application) initLookupTable(); for (int step = 0; step < num_steps; step++) { PointD pt = Utility.Lerp(start, end, (float)step / num_steps); int x = (int)pt.X, y = (int)pt.Y; Gdk.Rectangle surface_rect = new Gdk.Rectangle(0, 0, surf.Width, surf.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 > 0) && (dest_rect.Height > 0)) { //Allow Clipping through a temporary surface using (ImageSurface tmp_surface = copySurfacePart(surf, dest_rect)) { for (int iy = dest_rect.Top; iy < dest_rect.Bottom; iy++) { ColorBgra *srcRowPtr = tmp_surface.GetRowAddressUnchecked(iy - dest_rect.Top); int dy = ((iy - y) * LUT_Resolution) / rad; if (dy < 0) { dy = -dy; } byte[] lut_factor_row = lut_factor [dy]; for (int ix = dest_rect.Left; ix < dest_rect.Right; ix++) { ColorBgra col = *srcRowPtr; int dx = ((ix - x) * LUT_Resolution) / rad; if (dx < 0) { dx = -dx; } int force = lut_factor_row [dx]; //Note: premultiplied alpha is used! if (mouse_button == 3) { col.A = (byte)((col.A * force + bk_col_a * (255 - force)) / 255); col.R = (byte)((col.R * force + bk_col_r * (255 - force)) / 255); col.G = (byte)((col.G * force + bk_col_g * (255 - force)) / 255); col.B = (byte)((col.B * force + bk_col_b * (255 - force)) / 255); } else { col.A = (byte)(col.A * force / 255); col.R = (byte)(col.R * force / 255); col.G = (byte)(col.G * force / 255); col.B = (byte)(col.B * force / 255); } *srcRowPtr = col; srcRowPtr++; } } //Draw the final result on the surface pasteSurfacePart(g, tmp_surface, dest_rect); } } } }