def _get_rgb_array(self, cut=True):
        """ render the current canvas as a rgb array
        """
        buf = pixbufsurface.render_as_pixbuf(self.surface)
        w = buf.get_width()
        h = buf.get_height()

        # convert uint8 matrix whose shape is [w, h, 4]
        img = np.frombuffer(buf.get_pixels(), np.uint8).reshape(h, w, -1)
        img = img[:, :, :3]  # discard the alpha channel

        # cut out the canvas
        if cut:
            img = img[self.tile_offset:self.tile_offset + self.imsize,
                      self.tile_offset:self.tile_offset + self.imsize, :]

        return img
Example #2
0
def render_brush_preview_pixbuf(brushinfo, max_edge_tiles=4):
    """Renders brush preview images

    :param lib.brush.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)
        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)
Example #3
0
def render_brush_preview_pixbuf(brushinfo, max_edge_tiles=4):
    """Renders brush preview images

    :param lib.brush.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)
        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)