public void Render(Cairo.ImageSurface src, Cairo.ImageSurface dst, Gdk.Point offset, bool checker) { dst.Flush (); if (scale_factor.Ratio == 1) RenderOneToOne (src, dst, offset, checker); else if (scale_factor.Ratio < 1) RenderZoomIn (src, dst, offset, checker); else RenderZoomOut (src, dst, offset, destination_size, checker); dst.MarkDirty (); }
public void Render(List<Layer> layers, Cairo.ImageSurface dst, Gdk.Point offset) { dst.Flush (); if (scale_factor.Ratio == 1) RenderOneToOne (layers, dst, offset); else if (scale_factor.Ratio < 1) RenderZoomIn (layers, dst, offset); else RenderZoomOut (layers, dst, offset, destination_size); dst.MarkDirty (); }
public void Render (List<Layer> layers, Cairo.ImageSurface dst, Gdk.Point offset) { dst.Flush (); // Our rectangle of interest var r = new Gdk.Rectangle (offset, dst.GetBounds ().Size).ToCairoRectangle (); using (var g = new Cairo.Context (dst)) { // Create the transparent checkerboard background g.Translate (-offset.X, -offset.Y); g.FillRectangle (r, tranparent_pattern, new Cairo.PointD (offset.X, offset.Y)); for (var i = 0; i < layers.Count; i++) { var layer = layers[i]; // If we're in LivePreview, substitute current layer with the preview layer if (layer == PintaCore.Layers.CurrentLayer && PintaCore.LivePreview.IsEnabled) layer = CreateLivePreviewLayer (layer); // If the layer is offset, handle it here if (!layer.Transform.IsIdentity ()) layer = CreateOffsetLayer (layer); // No need to resize the surface if we're at 100% zoom if (scale_factor.Ratio == 1) layer.Draw (g, layer.Surface, layer.Opacity, false); else { using (var scaled = new Cairo.ImageSurface (Cairo.Format.Argb32, dst.Width, dst.Height)) { g.Save (); // Have to undo the translate set above g.Translate (offset.X, offset.Y); CopyScaled (layer.Surface, scaled, r.ToGdkRectangle ()); layer.Draw (g, scaled, layer.Opacity, false); g.Restore (); } } } } // If we are at least 200% and grid is requested, draw it if (enable_pixel_grid && PintaCore.Actions.View.PixelGrid.Active && scale_factor.Ratio <= 0.5d) RenderPixelGrid (dst, offset); dst.MarkDirty (); }
private unsafe void CopyScaledZoomOut (Cairo.ImageSurface src, Cairo.ImageSurface dst, Rectangle roi) { // Tell Cairo we need the latest raw data dst.Flush (); const int fpShift = 12; const int fpFactor = (1 << fpShift); var source_size = src.GetBounds ().Size; // Find destination bounds var dst_left = (int)(((long)roi.X * fpFactor * (long)source_size.Width) / (long)destination_size.Width); var dst_top = (int)(((long)roi.Y * fpFactor * (long)source_size.Height) / (long)destination_size.Height); var dst_right = (int)(((long)(roi.X + dst.Width) * fpFactor * (long)source_size.Width) / (long)destination_size.Width); var dst_bottom = (int)(((long)(roi.Y + dst.Height) * fpFactor * (long)source_size.Height) / (long)destination_size.Height); var dx = (dst_right - dst_left) / dst.Width; var dy = (dst_bottom - dst_top) / dst.Height; // Cache pointers to surface raw data and sizes var src_ptr = (ColorBgra*)src.DataPtr; var dst_ptr = (ColorBgra*)dst.DataPtr; var src_width = src.Width; var dst_width = dst.Width; var dst_height = dst.Height; for (int dstRow = 0, fDstY = dst_top; dstRow < dst_height && fDstY < dst_bottom; ++dstRow, fDstY += dy) { var srcY1 = fDstY >> fpShift; // y var srcY2 = (fDstY + (dy >> 2)) >> fpShift; // y + 0.25 var srcY3 = (fDstY + (dy >> 1)) >> fpShift; // y + 0.50 var srcY4 = (fDstY + (dy >> 1) + (dy >> 2)) >> fpShift; // y + 0.75 var src1 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY1); var src2 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY2); var src3 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY3); var src4 = src.GetRowAddressUnchecked (src_ptr, src_width, srcY4); var dstPtr = dst.GetRowAddressUnchecked (dst_ptr, dst_width, dstRow); var checkerY = dstRow + roi.Y; var checkerX = roi.X; var maxCheckerX = checkerX + dst.Width; for (var fDstX = dst_left; checkerX < maxCheckerX && fDstX < dst_right; ++checkerX, fDstX += dx) { var srcX1 = (fDstX + (dx >> 2)) >> fpShift; // x + 0.25 var srcX2 = (fDstX + (dx >> 1) + (dx >> 2)) >> fpShift; // x + 0.75 var srcX3 = fDstX >> fpShift; // x var srcX4 = (fDstX + (dx >> 1)) >> fpShift; // x + 0.50 var p1 = src1 + srcX1; var p2 = src2 + srcX2; var p3 = src3 + srcX3; var p4 = src4 + srcX4; var r = (2 + p1->R + p2->R + p3->R + p4->R) >> 2; var g = (2 + p1->G + p2->G + p3->G + p4->G) >> 2; var b = (2 + p1->B + p2->B + p3->B + p4->B) >> 2; var a = (2 + p1->A + p2->A + p3->A + p4->A) >> 2; // Copy color to destination *dstPtr++ = ColorBgra.FromUInt32 ((uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)a << 24)); } } // Tell Cairo we changed the raw data dst.MarkDirty (); }
private unsafe void CopyScaledZoomIn (Cairo.ImageSurface src, Cairo.ImageSurface dst, Rectangle roi) { // Tell Cairo we need the latest raw data dst.Flush (); EnsureLookupTablesCreated (); // Cache pointers to surface raw data var src_ptr = (ColorBgra*)src.DataPtr; var dst_ptr = (ColorBgra*)dst.DataPtr; // Cache surface sizes var src_width = src.Width; var dst_width = dst.Width; var dst_height = dst.Height; for (var dst_row = 0; dst_row < dst_height; ++dst_row) { // For each dest row, look up the src row to copy from var nnY = dst_row + roi.Y; var srcY = d2sLookupY[nnY]; // Get pointers to src and dest rows var dst_row_ptr = dst.GetRowAddressUnchecked (dst_ptr, dst_width, dst_row); var src_row_ptr = src.GetRowAddressUnchecked (src_ptr, src_width, srcY); for (var dstCol = 0; dstCol < dst_width; ++dstCol) { // Look up the src column to copy from var nnX = dstCol + roi.X; var srcX = d2sLookupX[nnX]; // Copy source to destination *dst_row_ptr++ = *(src_row_ptr + srcX); } } // Tell Cairo we changed the raw data dst.MarkDirty (); }
private unsafe void DrawText(Cairo.ImageSurface dst, string textFont, string text, Point pt, Size measuredSize, bool antiAliasing, Cairo.ImageSurface brush8x8) { Point pt2 = pt; Size measuredSize2 = measuredSize; int offset = FontHeight; pt.X -= offset; measuredSize.Width += 2 * offset; Rectangle dstRect = new Rectangle (pt, measuredSize); Rectangle dstRectClipped = Rectangle.Intersect (dstRect, PintaCore.Layers.ToolLayer.Surface.GetBounds ()); PintaCore.Layers.ToolLayer.Clear (); if (dstRectClipped.Width == 0 || dstRectClipped.Height == 0) { return; } // We only use the first 8,8 of brush using (Cairo.Context toolctx = new Cairo.Context (PintaCore.Layers.ToolLayer.Surface)) { //toolctx.FillRectangle (new Cairo.Rectangle(0, 0, 800, 600), new Cairo.Color (0, 0, 0)); toolctx.FillRectangle (dstRect.ToCairoRectangle (), new Cairo.Color (1, 1, 1)); Cairo.ImageSurface surf = PintaCore.Layers.ToolLayer.Surface; //TODO find how create a surface a of a particular area of a bigger surface! //for moment work with the whole surface! if (measuredSize.Width > 0 && measuredSize.Height > 0) { //dstRectClipped using (Cairo.Context ctx = new Cairo.Context (PintaCore.Layers.ToolLayer.Surface)) { Cairo.TextExtents te = TextExtents (ctx, text); //new Cairo.PointD(dstRect.X - dstRectClipped.X + offset, dstRect.Y - dstRectClipped.Y), ctx.DrawText (new Cairo.PointD (dstRect.X + offset - te.XBearing, dstRect.Y - te.YBearing), textFont, FontSlant, FontWeight, FontSize, PintaCore.Palette.PrimaryColor, text, antiAliasing); if (underscore_btn.Active) { int lineSize = 1; Cairo.FontExtents fe = FontExtents (ctx, text); ctx.DrawLine (new Cairo.PointD (pt2.X, dstRect.Bottom + fe.Descent), new Cairo.PointD (dstRect.Right - offset, dstRect.Bottom + fe.Descent), PintaCore.Palette.PrimaryColor, lineSize); } } PintaCore.Workspace.Invalidate (); } // Mask out anything that isn't within the user's clip region (selected region) using (Region clip = Region.Rectangle (PintaCore.Layers.SelectionPath.GetBounds ())) { clip.Xor (Region.Rectangle (dstRectClipped)); // invert clip.Intersect (Region.Rectangle (new Rectangle (pt, measuredSize))); toolctx.FillRegion (clip, new Cairo.Color (1, 1, 1, 1)); } int skipX; if (pt.X < 0) { skipX = -pt.X; } else { skipX = 0; } int xEnd = Math.Min (dst.Width, pt.X + measuredSize.Width); bool blending = alphablending_btn.Active; dst.Flush (); //if (dst.IsColumnVisible(pt.X + skipX)) //{ for (int y = pt.Y; y < pt.Y + measuredSize.Height; ++y) { //if (!dst.IsRowVisible(y)) //{ // continue; //} ColorBgra* dstPtr = dst.GetPointAddressUnchecked (pt.X + skipX, y); ColorBgra* srcPtr = PintaCore.Layers.ToolLayer.Surface.GetPointAddress (pt.X + skipX, y); ColorBgra* brushPtr = brush8x8.GetRowAddressUnchecked (y & 7); for (int x = pt.X + skipX; x < xEnd; ++x) { ColorBgra srcPixel = *srcPtr; ColorBgra dstPixel = *dstPtr; ColorBgra brushPixel = brushPtr[x & 7]; int alpha = ((255 - srcPixel.R) * brushPixel.A) / 255; // we could use srcPixel.R, .G, or .B -- the choice here is arbitrary brushPixel.A = (byte)alpha; // could use R, G, or B -- arbitrary choice if (srcPtr->R == 255) { // do nothing -- leave dst alone } else if (alpha == 255 || !blending) { // copy it straight over *dstPtr = brushPixel; } else { // do expensive blending *dstPtr = UserBlendOps.NormalBlendOp.ApplyStatic (dstPixel, brushPixel); } ++dstPtr; ++srcPtr; } } //} dst.MarkDirty (); } }
public unsafe void Render(Cairo.ImageSurface dst, Gdk.Point offset) { if (cr.ScaleFactor > new ScaleFactor (1, 2)) return; int[] d2SLookupX = cr.Dst2SrcLookupX; int[] d2SLookupY = cr.Dst2SrcLookupY; int[] s2DLookupX = cr.Src2DstLookupX; int[] s2DLookupY = cr.Src2DstLookupY; ColorBgra[] blackAndWhite = new ColorBgra[2] { ColorBgra.White, ColorBgra.Black }; // draw horizontal lines int dstHeight = dst.Height; int dstWidth = dst.Width; int dstStride = dst.Stride; int sTop = d2SLookupY[offset.Y]; int sBottom = d2SLookupY[offset.Y + dstHeight]; dst.Flush (); for (int srcY = sTop; srcY <= sBottom; ++srcY) { int dstY = s2DLookupY[srcY]; int dstRow = dstY - offset.Y; if (dstRow >= 0 && dstRow < dstHeight) { ColorBgra* dstRowPtr = dst.GetRowAddressUnchecked (dstRow); ColorBgra* dstRowEndPtr = dstRowPtr + dstWidth; dstRowPtr += offset.X & 1; while (dstRowPtr < dstRowEndPtr) { *dstRowPtr = ColorBgra.Black; dstRowPtr += 2; } } } // draw vertical lines int sLeft = d2SLookupX[offset.X]; int sRight = d2SLookupX[offset.X + dstWidth]; for (int srcX = sLeft; srcX <= sRight; ++srcX) { int dstX = s2DLookupX[srcX]; int dstCol = dstX - offset.X; if (dstCol >= 0 && dstCol < dstWidth) { byte* dstColPtr = (byte*)dst.GetPointAddress (dstCol, 0); byte* dstColEndPtr = dstColPtr + dstStride * dstHeight; dstColPtr += (offset.Y & 1) * dstStride; while (dstColPtr < dstColEndPtr) { *((ColorBgra*)dstColPtr) = ColorBgra.Black; dstColPtr += 2 * dstStride; } } } dst.MarkDirty (); }