class SmudgeBrushStroke (AbstractBrushStroke): def __init__(self, goghview, current_layer_key, brush_options): AbstractBrushStroke.__init__(self, goghview, current_layer_key, brush_options) self.brush_options = brush_options self.bounding_rectangle = None self.brush_provider = BrushProvider(brush_options) self.x_prev, self.y_prev = None, None def trim_to_fit(self, x1, x2, w): return (max(x1, 0), min(x2, w)) def apply_brush_stroke(self, x0, y0, x1, y1, intermediate_coords, max_pressure): layer = self.goghdoc.layer_for_key(self.current_layer_key) pix_array = layer.pixbuf.get_pixels_array() smudge_amt = self.brush_options.smudge_amount for x, y, pressure in intermediate_coords: adj_brush = self.brush_provider.get_adjusted_brush(pressure, x-int(x), y-int(y)) brush_w, brush_h = adj_brush.shape[0], adj_brush.shape[1] brush = zeros((brush_w, brush_h, 1), float) brush[...,0] = adj_brush[...] xt = int(floor(x))-adj_brush.shape[1]//2 yt = int(floor(y))-adj_brush.shape[0]//2 if self.x_prev and self.y_prev: x_ofs, y_ofs = min(self.x_prev, xt, 0), min(self.y_prev, yt, 0) x_ofs2 = max(xt+brush_w, self.x_prev+brush_w, self.goghdoc.width)-self.goghdoc.width y_ofs2 = max(yt+brush_w, self.y_prev+brush_h, self.goghdoc.height)-self.goghdoc.height if (x_ofs2-x_ofs<brush_w) and (y_ofs2-y_ofs<brush_h): brush_fragment = brush[-y_ofs:brush_h-y_ofs2,-x_ofs:brush_w-x_ofs2] t = pix_array[yt-y_ofs:yt+brush_h-y_ofs2, xt-x_ofs:xt+brush_w-x_ofs2]*(1-smudge_amt)+pix_array[self.y_prev-y_ofs:self.y_prev+brush_h-y_ofs2, self.x_prev-x_ofs:self.x_prev+brush_w-x_ofs2]*smudge_amt pix_array[yt-y_ofs:yt+brush_h-y_ofs2, xt-x_ofs:xt+brush_w-x_ofs2] = (minimum(255, 0.5+pix_array[yt-y_ofs:yt+brush_h-y_ofs2, xt-x_ofs:xt+brush_w-x_ofs2]*(1-brush_fragment)+t*brush_fragment)).astype(uint8)[:,:] self.x_prev, self.y_prev = xt, yt self.goghdoc.combine_layers(self.bounding_rectangle.x, self.bounding_rectangle.y, self.bounding_rectangle.width, self.bounding_rectangle.height)