public Cairo.Pattern GetPattern(ApplicationContext actx, double scaleFactor) { if (pattern == null || currentScaleFactor != scaleFactor) { if (pattern != null) { pattern.Dispose(); } Gdk.Pixbuf pb = ((GtkImage)Image.Backend).GetBestFrame(actx, scaleFactor, Image.Size.Width, Image.Size.Height, false); using (var imgs = new Cairo.ImageSurface(Cairo.Format.ARGB32, (int)(Image.Size.Width * scaleFactor), (int)(Image.Size.Height * scaleFactor))) { var ic = new Cairo.Context(imgs); ic.Scale((double)imgs.Width / (double)pb.Width, (double)imgs.Height / (double)pb.Height); Gdk.CairoHelper.SetSourcePixbuf(ic, pb, 0, 0); ic.Paint(); imgs.Flush(); ((IDisposable)ic).Dispose(); pattern = new Cairo.SurfacePattern(imgs); } pattern.Extend = Cairo.Extend.Repeat; var cm = new Cairo.Matrix(); cm.Scale(scaleFactor, scaleFactor); pattern.Matrix = cm; currentScaleFactor = scaleFactor; } return(pattern); }
void Flush(bool recreate) { #if GTK2 if (Control != null) { // Analysis disable once RedundantCast - backward compatibility ((IDisposable)Control).Dispose(); if (recreate) { if (surface != null) { Control = new Cairo.Context(surface); } else if (drawable != null) { Control = Gdk.CairoHelper.Create(drawable); } } } #endif if (image != null) { var handler = (BitmapHandler)image.Handler; surface.Flush(); handler.Surface = surface; if (!recreate) { surface = null; } } }
public void Render(List <Layer> layers, Cairo.ImageSurface dst, Point offset) { dst.Flush(); // Our rectangle of interest var r = new Rectangle(offset, dst.GetBounds().Size).ToCairoRectangle(); var doc = PintaCore.Workspace.ActiveDocument; 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 == doc.Layers.CurrentUserLayer && 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 = CairoExtensions.CreateImageSurface(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.Value && scale_factor.Ratio <= 0.5d) { RenderPixelGrid(dst, offset); } dst.MarkDirty(); }
public override void BeginUpdate() { Interlocked.Increment(ref lock_count); if (lock_count > 1) { return; } surface.Flush(); }
// Runs on a background thread. void RenderTile(int renderId, int threadId, int tileIndex) { Exception exception = null; Gdk.Rectangle bounds = new Gdk.Rectangle(); try { bounds = GetTileBounds(tileIndex); if (!cancel_render_flag) { dest_surface.Flush(); effect.Render(source_surface, dest_surface, new [] { bounds }); dest_surface.MarkDirty(bounds.ToCairoRectangle()); } } catch (Exception ex) { exception = ex; Debug.WriteLine("AsyncEffectRenderer Error while rendering effect: " + effect.Name + " exception: " + ex.Message + "\n" + ex.StackTrace); } // Ignore completions of tiles after a cancel or from a previous render. if (!IsRendering || renderId != render_id) { return; } // Update bounds to be shown on next expose. lock (updated_lock) { if (is_updated) { updated_x1 = Math.Min(bounds.X, updated_x1); updated_y1 = Math.Min(bounds.Y, updated_y1); updated_x2 = Math.Max(bounds.X + bounds.Width, updated_x2); updated_y2 = Math.Max(bounds.Y + bounds.Height, updated_y2); } else { is_updated = true; updated_x1 = bounds.X; updated_y1 = bounds.Y; updated_x2 = bounds.X + bounds.Width; updated_y2 = bounds.Y + bounds.Height; } } if (exception != null) { lock (render_exceptions) { render_exceptions.Add(exception); } } }
public override object Create(object img) { Gdk.Pixbuf pb = (Gdk.Pixbuf)img; var imgs = new Cairo.ImageSurface (Cairo.Format.ARGB32, pb.Width, pb.Height); var ic = new Cairo.Context (imgs); Gdk.CairoHelper.SetSourcePixbuf (ic, pb, 0, 0); ic.Paint (); imgs.Flush (); ((IDisposable)ic).Dispose (); var p = new Cairo.SurfacePattern (imgs); p.Extend = Cairo.Extend.Repeat; return p; }
public object Create(object img) { Gdk.Pixbuf pb = (Gdk.Pixbuf)img; var imgs = new Cairo.ImageSurface(Cairo.Format.ARGB32, pb.Width, pb.Height); var ic = new Cairo.Context(imgs); Gdk.CairoHelper.SetSourcePixbuf(ic, pb, 0, 0); ic.Paint(); imgs.Flush(); ((IDisposable)ic).Dispose(); var p = new Cairo.SurfacePattern(imgs); p.Extend = Cairo.Extend.Repeat; return(p); }
public void Flush() { if (image != null) { var handler = (BitmapHandler)image.Handler; Gdk.Pixbuf pb = handler.GetPixbuf(Size.MaxValue); if (pb != null) { surface.Flush(); var bd = handler.Lock(); unsafe { var srcrow = (byte *)surface.DataPtr; var destrow = (byte *)bd.Data; for (int y = 0; y < image.Size.Height; y++) { var src = (uint *)srcrow; var dest = (uint *)destrow; for (int x = 0; x < image.Size.Width; x++) { *dest = bd.TranslateArgbToData(*src); dest++; src++; } destrow += bd.ScanWidth; srcrow += surface.Stride; } } handler.Unlock(bd); } } #if GTK2 if (Control != null) { // Analysis disable once RedundantCast - backward compatibility ((IDisposable)Control).Dispose(); if (surface != null) { Control = new Cairo.Context(surface); } else if (drawable != null) { Control = Gdk.CairoHelper.Create(drawable); } } #endif }
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(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 Flush() { if (image != null) { var handler = (BitmapHandler)image.Handler; Gdk.Pixbuf pb = (Gdk.Pixbuf)image.ControlObject; if (pb != null) { surface.Flush(); var bd = handler.Lock(); unsafe { byte *srcrow = (byte *)surface.DataPtr; byte *destrow = (byte *)bd.Data; for (int y = 0; y < image.Size.Height; y++) { uint *src = (uint *)srcrow; uint *dest = (uint *)destrow; for (int x = 0; x < image.Size.Width; x++) { *dest = bd.TranslateArgbToData(*src); dest++; src++; } destrow += bd.ScanWidth; srcrow += surface.Stride; } } handler.Unlock(bd); } } if (Control != null) { ((IDisposable)Control).Dispose(); if (surface != null) { this.Control = new Cairo.Context(surface); } else if (drawable != null) { this.Control = Gdk.CairoHelper.Create(drawable); } } }
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(); }
public Cairo.Pattern GetPattern (ApplicationContext actx, double scaleFactor) { if (pattern == null || currentScaleFactor != scaleFactor) { if (pattern != null) pattern.Dispose (); Gdk.Pixbuf pb = ((GtkImage)Image.Backend).GetBestFrame (actx, scaleFactor, Image.Size.Width, Image.Size.Height, false); using (var imgs = new Cairo.ImageSurface (Cairo.Format.ARGB32, (int)(Image.Size.Width * scaleFactor), (int)(Image.Size.Height * scaleFactor))) { var ic = new Cairo.Context (imgs); ic.Scale ((double)imgs.Width / (double)pb.Width, (double)imgs.Height / (double)pb.Height); Gdk.CairoHelper.SetSourcePixbuf (ic, pb, 0, 0); ic.Paint (); imgs.Flush (); ((IDisposable)ic).Dispose (); pattern = new Cairo.SurfacePattern (imgs); } pattern.Extend = Cairo.Extend.Repeat; var cm = new Cairo.Matrix (); cm.Scale (scaleFactor, scaleFactor); pattern.Matrix = cm; currentScaleFactor = scaleFactor; } return pattern; }
/// <summary> /// Copy image data to the layer's surface. /// </summary> /// <param name="image_data">Array of image data in RGBA format.</param> private static unsafe void CopyToSurface(byte[] image_data, Cairo.ImageSurface surf) { if (image_data.Length != surf.Data.Length) { throw new ArgumentException("Mismatched image sizes"); } surf.Flush(); ColorBgra *dst = (ColorBgra *)surf.DataPtr; int len = image_data.Length / ColorBgra.SizeOf; fixed(byte *src_bytes = image_data) { ColorBgra *src = (ColorBgra *)src_bytes; for (int i = 0; i < len; ++i) { *dst++ = *src++; } } surf.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(); }
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(); }