def cairo_request(self): """Access via a temporary Cairo context. Modifications are copied back into the backing pixbuf when the context manager finishes. """ # Make a Cairo surface copy of the subpixbuf surf = cairo.ImageSurface( cairo.FORMAT_ARGB32, self.pixbuf.get_width(), self.pixbuf.get_height(), ) cr = cairo.Context(surf) Gdk.cairo_set_source_pixbuf(cr, self.pixbuf, 0, 0) cr.paint() # User can modify its content with Cairo operations yield cr # Put the modified data back into the tile-aligned pixbuf. dx = self.x - self.ex dy = self.y - self.ey pixbuf = Gdk.pixbuf_get_from_surface(surf, 0, 0, self.w, self.h) pixbuf.copy_area(0, 0, self.w, self.h, self.epixbuf, dx, dy)
def _image_surface_to_pixbuf(surf): """Convert a Cairo surface to a GdkPixbuf""" w = surf.get_width() h = surf.get_height() return Gdk.pixbuf_get_from_surface(surf, 0, 0, w, h)
def render_brush_preview_pixbuf(brushinfo, max_edge_tiles=4): """Renders brush preview images :param BrushInfo brushinfo: settings to render :param int max_edge_tiles: Use at most this many tiles along an edge :returns: Preview image, at 128x128 pixels :rtype: GdkPixbuf This generates the preview image (128px icon) used for brushes which don't have saved ones. These include brushes picked from .ORA files where the parent_brush_name doesn't correspond to a brush in the user's MyPaint brushes - they're used as the default, and for the Auto button in the Brush Icon editor. Brushstrokes are inherently unpredictable in size, so the allowable area is grown until the brush fits or until the rendering becomes too big. `max_edge_tiles` limits this growth. """ assert max_edge_tiles >= 1 brushinfo = brushinfo.clone() # avoid capturing a ref brush = Brush(brushinfo) surface = lib.tiledsurface.Surface() n = lib.tiledsurface.N for size_in_tiles in range(1, max_edge_tiles): width = n * size_in_tiles height = n * size_in_tiles surface.clear() fg, spiral = _brush_preview_bg_fg(surface, size_in_tiles, brushinfo) brushinfo.set_color_rgb(fg) brush.reset() # Curve shape = _variable_pressure_scribble(width, height, size_in_tiles) surface.begin_atomic() for dt, x, y, p, xt, yt in shape: brush.stroke_to(surface.backend, x, y, p, xt, yt, dt, 1.0, 0.0, 0.0) surface.end_atomic() # Check rendered size tposs = surface.tiledict.keys() outside = min({tx for tx, ty in tposs}) < 0 outside = outside or (min({ty for tx, ty in tposs}) < 0) outside = outside or (max({tx for tx, ty in tposs}) >= size_in_tiles) outside = outside or (max({ty for tx, ty in tposs}) >= size_in_tiles) if not outside: break # Convert to pixbuf at the right scale rect = (0, 0, width, height) pixbuf = render_as_pixbuf(surface, *rect, alpha=True) if max(width, height) != 128: interp = (GdkPixbuf.InterpType.NEAREST if max(width, height) < 128 else GdkPixbuf.InterpType.BILINEAR) pixbuf = pixbuf.scale_simple(128, 128, interp) # Composite over a checquered bg via Cairo: shows erases size = gui.style.ALPHA_CHECK_SIZE nchecks = int(128 // size) cairo_surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 128) cr = cairo.Context(cairo_surf) render_checks(cr, size, nchecks) Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0) cr.paint() cairo_surf.flush() return Gdk.pixbuf_get_from_surface(cairo_surf, 0, 0, 128, 128)
def make_preview(thumb, preview_size): """Convert a layer's thumbnail into a nice preview image.""" # Check size check_size = 2 while check_size < (preview_size / 6) and check_size < 16: check_size *= 2 blank = GdkPixbuf.Pixbuf.new( GdkPixbuf.Colorspace.RGB, True, 8, preview_size, preview_size, ) blank.fill(0x00000000) if thumb is None: thumb = blank # Make a square of chex preview = blank.composite_color_simple( dest_width=preview_size, dest_height=preview_size, interp_type=GdkPixbuf.InterpType.NEAREST, overall_alpha=255, check_size=check_size, color1=0xff707070, color2=0xff808080, ) w = thumb.get_width() h = thumb.get_height() scale = preview_size / max(w, h) w *= scale h *= scale x = (preview_size - w) // 2 y = (preview_size - h) // 2 thumb.composite( dest=preview, dest_x=x, dest_y=y, dest_width=w, dest_height=h, offset_x=x, offset_y=y, scale_x=scale, scale_y=scale, interp_type=GdkPixbuf.InterpType.BILINEAR, overall_alpha=255, ) # Add some very minor decorations.. surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, preview_size, preview_size) cr = cairo.Context(surf) Gdk.cairo_set_source_pixbuf(cr, preview, 0, 0) cr.paint() cr.set_source_rgba(1, 1, 1, 0.1) cr.rectangle(0.5, 0.5, preview_size - 1, preview_size - 1) cr.set_line_width(1.0) cr.stroke() surf.flush() preview = Gdk.pixbuf_get_from_surface( surf, 0, 0, preview_size, preview_size, ) return preview