static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); gboolean need_fill = FALSE; gdouble r,g,b,a; if (input) { gegl_buffer_copy (input, result, output, result); } else { gegl_buffer_clear (output, result); } if (o->opacity > 0.0001 && o->color) { gegl_color_get_rgba (o->color, &r,&g,&b,&a); a *= o->opacity; if (a>0.001) need_fill=TRUE; } if (need_fill) { GStaticMutex mutex = G_STATIC_MUTEX_INIT; cairo_t *cr; cairo_surface_t *surface; guchar *data; g_static_mutex_lock (&mutex); data = (void*)gegl_buffer_linear_open (output, result, NULL, babl_format ("B'aG'aR'aA u8")); surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, result->width, result->height, result->width * 4); cr = cairo_create (surface); cairo_translate (cr, -result->x, -result->y); if (g_str_equal (o->fill_rule, "evenodd")) cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); gegl_path_cairo_play (o->d, cr); cairo_set_source_rgba (cr, r,g,b,a); cairo_fill (cr); cairo_destroy (cr); gegl_buffer_linear_close (output, data); g_static_mutex_unlock (&mutex); } return TRUE; }
void gegl_cache_invalidate (GeglCache *self, const GeglRectangle *roi) { #if 0 if (roi) { gegl_buffer_clear (GEGL_BUFFER (self), roi); } else { g_warning ("XXX: full invalidation of GeglCache NYI\n"); } #endif g_mutex_lock (self->mutex); if (roi) { GeglRectangle expanded = gegl_rectangle_expand (roi); GeglRegion *temp_region; temp_region = gegl_region_rectangle (&expanded); gegl_region_subtract (self->valid_region, temp_region); gegl_region_destroy (temp_region); g_signal_emit (self, gegl_cache_signals[INVALIDATED], 0, roi, NULL); } else { GeglRectangle rect = { 0, 0, 0, 0 }; /* should probably be the extent of the cache */ if (self->valid_region) gegl_region_destroy (self->valid_region); self->valid_region = gegl_region_new (); g_signal_emit (self, gegl_cache_signals[INVALIDATED], 0, &rect, NULL); } g_mutex_unlock (self->mutex); }
static void gimp_channel_combine_clear (GimpChannel *mask, const GeglRectangle *rect) { GeglBuffer *buffer; GeglRectangle area; GeglRectangle update_area; if (mask->bounds_known && mask->empty) return; buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); if (rect) { if (rect->width <= 0 || rect->height <= 0) return; if (mask->bounds_known) { if (! gegl_rectangle_intersect (&area, GEGL_RECTANGLE (mask->x1, mask->y1, mask->x2 - mask->x1, mask->y2 - mask->y1), rect)) { return; } } else { area = *rect; } update_area = area; } else { if (mask->bounds_known) { area.x = mask->x1; area.y = mask->y1; area.width = mask->x2 - mask->x1; area.height = mask->y2 - mask->y1; } else { area.x = 0; area.y = 0; area.width = gimp_item_get_width (GIMP_ITEM (mask)); area.height = gimp_item_get_height (GIMP_ITEM (mask)); } update_area = area; gimp_gegl_rectangle_align_to_tile_grid (&area, &area, buffer); } gegl_buffer_clear (buffer, &area); gimp_drawable_update (GIMP_DRAWABLE (mask), update_area.x, update_area.y, update_area.width, update_area.height); }
void gimp_source_core_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, GimpSymmetry *sym) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options); GimpDynamics *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics; GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); GimpPickable *src_pickable = NULL; GeglBuffer *src_buffer = NULL; GeglRectangle src_rect; gint base_src_offset_x; gint base_src_offset_y; gint src_offset_x; gint src_offset_y; GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; gint paint_area_offset_x; gint paint_area_offset_y; gint paint_area_width; gint paint_area_height; gdouble fade_point; gdouble opacity; GeglNode *op; GimpCoords *origin; GimpCoords *coords; gint n_strokes; gint i; fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); origin = gimp_symmetry_get_origin (sym); /* Some settings are based on the original stroke. */ opacity = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_OPACITY, origin, paint_options, fade_point); if (opacity == 0.0) return; base_src_offset_x = source_core->offset_x; base_src_offset_y = source_core->offset_y; if (gimp_source_core_use_source (source_core, options)) { src_pickable = GIMP_PICKABLE (source_core->src_drawable); if (options->sample_merged) { GimpImage *src_image = gimp_pickable_get_image (src_pickable); gint off_x, off_y; src_pickable = GIMP_PICKABLE (src_image); gimp_item_get_offset (GIMP_ITEM (source_core->src_drawable), &off_x, &off_y); base_src_offset_x += off_x; base_src_offset_y += off_y; } gimp_pickable_flush (src_pickable); } gimp_brush_core_eval_transform_dynamics (GIMP_BRUSH_CORE (paint_core), drawable, paint_options, origin); n_strokes = gimp_symmetry_get_size (sym); for (i = 0; i < n_strokes; i++) { coords = gimp_symmetry_get_coords (sym, i); paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable, paint_options, coords, &paint_buffer_x, &paint_buffer_y, NULL, NULL); if (! paint_buffer) continue; paint_area_offset_x = 0; paint_area_offset_y = 0; paint_area_width = gegl_buffer_get_width (paint_buffer); paint_area_height = gegl_buffer_get_height (paint_buffer); src_offset_x = base_src_offset_x; src_offset_y = base_src_offset_y; if (gimp_source_core_use_source (source_core, options)) { /* When using a source, use the same for every stroke. */ src_offset_x = src_offset_x - coords->x + origin->x; src_offset_y = src_offset_y - coords->y + origin->y; src_buffer = GIMP_SOURCE_CORE_GET_CLASS (source_core)->get_source (source_core, drawable, paint_options, src_pickable, src_offset_x, src_offset_y, paint_buffer, paint_buffer_x, paint_buffer_y, &paint_area_offset_x, &paint_area_offset_y, &paint_area_width, &paint_area_height, &src_rect); if (! src_buffer) continue; } /* Set the paint buffer to transparent */ gegl_buffer_clear (paint_buffer, NULL); op = gimp_symmetry_get_operation (sym, i, gegl_buffer_get_width (paint_buffer), gegl_buffer_get_height (paint_buffer)); GIMP_SOURCE_CORE_GET_CLASS (source_core)->motion (source_core, drawable, paint_options, coords, op, opacity, src_pickable, src_buffer, &src_rect, src_offset_x, src_offset_y, paint_buffer, paint_buffer_x, paint_buffer_y, paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height); if (src_buffer) g_object_unref (src_buffer); } }
void gimp_source_core_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options); GimpDynamics *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics; GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); GimpPickable *src_pickable = NULL; GeglBuffer *src_buffer = NULL; GeglRectangle src_rect; gint src_offset_x; gint src_offset_y; GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; gint paint_area_offset_x; gint paint_area_offset_y; gint paint_area_width; gint paint_area_height; gdouble fade_point; gdouble opacity; fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); opacity = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_OPACITY, coords, paint_options, fade_point); if (opacity == 0.0) return; src_offset_x = source_core->offset_x; src_offset_y = source_core->offset_y; if (gimp_source_core_use_source (source_core, options)) { src_pickable = GIMP_PICKABLE (source_core->src_drawable); if (options->sample_merged) { GimpImage *src_image = gimp_pickable_get_image (src_pickable); gint off_x, off_y; src_pickable = GIMP_PICKABLE (src_image); gimp_item_get_offset (GIMP_ITEM (source_core->src_drawable), &off_x, &off_y); src_offset_x += off_x; src_offset_y += off_y; } gimp_pickable_flush (src_pickable); } paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable, paint_options, coords, &paint_buffer_x, &paint_buffer_y); if (! paint_buffer) return; paint_area_offset_x = 0; paint_area_offset_y = 0; paint_area_width = gegl_buffer_get_width (paint_buffer); paint_area_height = gegl_buffer_get_height (paint_buffer); if (gimp_source_core_use_source (source_core, options)) { src_buffer = GIMP_SOURCE_CORE_GET_CLASS (source_core)->get_source (source_core, drawable, paint_options, src_pickable, src_offset_x, src_offset_y, paint_buffer, paint_buffer_x, paint_buffer_y, &paint_area_offset_x, &paint_area_offset_y, &paint_area_width, &paint_area_height, &src_rect); if (! src_buffer) return; } /* Set the paint buffer to transparent */ gegl_buffer_clear (paint_buffer, NULL); GIMP_SOURCE_CORE_GET_CLASS (source_core)->motion (source_core, drawable, paint_options, coords, opacity, src_pickable, src_buffer, &src_rect, src_offset_x, src_offset_y, paint_buffer, paint_buffer_x, paint_buffer_y, paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height); if (src_buffer) g_object_unref (src_buffer); }
static GimpLayer * gimp_image_merge_layers (GimpImage *image, GimpContainer *container, GSList *merge_list, GimpContext *context, GimpMergeType merge_type) { GList *list; GSList *reverse_list = NULL; GSList *layers; GimpLayer *merge_layer; GimpLayer *layer; GimpLayer *bottom_layer; GimpParasiteList *parasites; gint count; gint x1, y1, x2, y2; gint off_x, off_y; gint position; gchar *name; GimpLayer *parent; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); layer = NULL; x1 = y1 = 0; x2 = y2 = 0; bottom_layer = NULL; parent = gimp_layer_get_parent (merge_list->data); /* Get the layer extents */ count = 0; while (merge_list) { layer = merge_list->data; gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y); switch (merge_type) { case GIMP_EXPAND_AS_NECESSARY: case GIMP_CLIP_TO_IMAGE: if (! count) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_get_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_get_height (GIMP_ITEM (layer)); } else { if (off_x < x1) x1 = off_x; if (off_y < y1) y1 = off_y; if ((off_x + gimp_item_get_width (GIMP_ITEM (layer))) > x2) x2 = (off_x + gimp_item_get_width (GIMP_ITEM (layer))); if ((off_y + gimp_item_get_height (GIMP_ITEM (layer))) > y2) y2 = (off_y + gimp_item_get_height (GIMP_ITEM (layer))); } if (merge_type == GIMP_CLIP_TO_IMAGE) { x1 = CLAMP (x1, 0, gimp_image_get_width (image)); y1 = CLAMP (y1, 0, gimp_image_get_height (image)); x2 = CLAMP (x2, 0, gimp_image_get_width (image)); y2 = CLAMP (y2, 0, gimp_image_get_height (image)); } break; case GIMP_CLIP_TO_BOTTOM_LAYER: if (merge_list->next == NULL) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_get_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_get_height (GIMP_ITEM (layer)); } break; case GIMP_FLATTEN_IMAGE: if (merge_list->next == NULL) { x1 = 0; y1 = 0; x2 = gimp_image_get_width (image); y2 = gimp_image_get_height (image); } break; } count ++; reverse_list = g_slist_prepend (reverse_list, layer); merge_list = g_slist_next (merge_list); } if ((x2 - x1) == 0 || (y2 - y1) == 0) return NULL; /* Start a merge undo group. */ name = g_strdup (gimp_object_get_name (layer)); if (merge_type == GIMP_FLATTEN_IMAGE || (gimp_drawable_is_indexed (GIMP_DRAWABLE (layer)) && ! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))) { GeglColor *color; GimpRGB bg; merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), gimp_image_get_layer_format (image, FALSE), gimp_object_get_name (layer), GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (! merge_layer) { g_warning ("%s: could not allocate merge layer.", G_STRFUNC); return NULL; } gimp_item_set_offset (GIMP_ITEM (merge_layer), x1, y1); /* get the background for compositing */ gimp_context_get_background (context, &bg); color = gimp_gegl_color_new (&bg); gegl_buffer_set_color (gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)), GEGL_RECTANGLE(0,0,x2-x1,y2-y1), color); g_object_unref (color); position = 0; } else { /* The final merged layer inherits the name of the bottom most layer * and the resulting layer has an alpha channel whether or not the * original did. Opacity is set to 100% and the MODE is set to normal. */ merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), gimp_drawable_get_format_with_alpha (GIMP_DRAWABLE (layer)), "merged layer", GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (!merge_layer) { g_warning ("%s: could not allocate merge layer", G_STRFUNC); return NULL; } gimp_item_set_offset (GIMP_ITEM (merge_layer), x1, y1); /* clear the layer */ gegl_buffer_clear (gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)), NULL); /* Find the index in the layer list of the bottom layer--we need this * in order to add the final, merged layer to the layer list correctly */ layer = reverse_list->data; position = gimp_container_get_n_children (container) - gimp_container_get_child_index (container, GIMP_OBJECT (layer)); } bottom_layer = layer; /* Copy the tattoo and parasites of the bottom layer to the new layer */ gimp_item_set_tattoo (GIMP_ITEM (merge_layer), gimp_item_get_tattoo (GIMP_ITEM (bottom_layer))); parasites = gimp_item_get_parasites (GIMP_ITEM (bottom_layer)); parasites = gimp_parasite_list_copy (parasites); gimp_item_set_parasites (GIMP_ITEM (merge_layer), parasites); g_object_unref (parasites); for (layers = reverse_list; layers; layers = g_slist_next (layers)) { GeglBuffer *merge_buffer; GeglBuffer *layer_buffer; GimpApplicator *applicator; GimpLayerModeEffects mode; layer = layers->data; gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y); /* DISSOLVE_MODE is special since it is the only mode that does not * work on the projection with the lower layer, but only locally on * the layers alpha channel. */ mode = gimp_layer_get_mode (layer); if (layer == bottom_layer && mode != GIMP_DISSOLVE_MODE) mode = GIMP_NORMAL_MODE; merge_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer)); layer_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer)); applicator = gimp_applicator_new (NULL, gimp_drawable_get_linear (GIMP_DRAWABLE (layer)), FALSE, FALSE); if (gimp_layer_get_mask (layer) && gimp_layer_get_apply_mask (layer)) { GeglBuffer *mask_buffer; mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer->mask)); gimp_applicator_set_mask_buffer (applicator, mask_buffer); gimp_applicator_set_mask_offset (applicator, - (x1 - off_x), - (y1 - off_y)); } gimp_applicator_set_src_buffer (applicator, merge_buffer); gimp_applicator_set_dest_buffer (applicator, merge_buffer); gimp_applicator_set_apply_buffer (applicator, layer_buffer); gimp_applicator_set_apply_offset (applicator, - (x1 - off_x), - (y1 - off_y)); gimp_applicator_set_mode (applicator, gimp_layer_get_opacity (layer), mode); gimp_applicator_blit (applicator, GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (merge_buffer), gegl_buffer_get_height (merge_buffer))); g_object_unref (applicator); gimp_image_remove_layer (image, layer, TRUE, NULL); } g_slist_free (reverse_list); gimp_object_take_name (GIMP_OBJECT (merge_layer), name); gimp_item_set_visible (GIMP_ITEM (merge_layer), TRUE, FALSE); /* if the type is flatten, remove all the remaining layers */ if (merge_type == GIMP_FLATTEN_IMAGE) { list = gimp_image_get_layer_iter (image); while (list) { layer = list->data; list = g_list_next (list); gimp_image_remove_layer (image, layer, TRUE, NULL); } gimp_image_add_layer (image, merge_layer, parent, position, TRUE); } else { /* Add the layer to the image */ gimp_image_add_layer (image, merge_layer, parent, gimp_container_get_n_children (container) - position + 1, TRUE); } gimp_drawable_update (GIMP_DRAWABLE (merge_layer), 0, 0, gimp_item_get_width (GIMP_ITEM (merge_layer)), gimp_item_get_height (GIMP_ITEM (merge_layer))); return merge_layer; }
static void gimp_mask_undo_pop (GimpUndo *undo, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { GimpMaskUndo *mask_undo = GIMP_MASK_UNDO (undo); GimpChannel *channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (undo)->item); GimpDrawable *drawable = GIMP_DRAWABLE (channel); GeglBuffer *new_buffer; const Babl *format; gint x1, y1, x2, y2; gint width = 0; gint height = 0; GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); if (gimp_channel_bounds (channel, &x1, &y1, &x2, &y2)) { new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, x2 - x1, y2 - y1), gimp_drawable_get_format (drawable)); gegl_buffer_copy (gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE (x1, y1, x2 - x1, y2 - y1), new_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); gegl_buffer_clear (gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE (x1, y1, x2 - x1, y2 - y1)); } else { new_buffer = NULL; } format = gimp_drawable_get_format (drawable); if (mask_undo->convert_format) { GeglBuffer *buffer; gint width = gimp_item_get_width (GIMP_ITEM (channel)); gint height = gimp_item_get_height (GIMP_ITEM (channel)); buffer = gimp_gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height), mask_undo->format); gegl_buffer_clear (buffer, NULL); gimp_drawable_set_buffer (drawable, FALSE, NULL, buffer); g_object_unref (buffer); } if (mask_undo->buffer) { width = gegl_buffer_get_width (mask_undo->buffer); height = gegl_buffer_get_height (mask_undo->buffer); gegl_buffer_copy (mask_undo->buffer, NULL, gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE (mask_undo->x, mask_undo->y, 0, 0)); g_object_unref (mask_undo->buffer); } /* invalidate the current bounds and boundary of the mask */ gimp_drawable_invalidate_boundary (drawable); if (mask_undo->buffer) { channel->empty = FALSE; channel->x1 = mask_undo->x; channel->y1 = mask_undo->y; channel->x2 = mask_undo->x + width; channel->y2 = mask_undo->y + height; } else { channel->empty = TRUE; channel->x1 = 0; channel->y1 = 0; channel->x2 = gimp_item_get_width (GIMP_ITEM (channel)); channel->y2 = gimp_item_get_height (GIMP_ITEM (channel)); } /* we know the bounds */ channel->bounds_known = TRUE; /* set the new mask undo parameters */ mask_undo->buffer = new_buffer; mask_undo->x = x1; mask_undo->y = y1; mask_undo->format = format; gimp_drawable_update (GIMP_DRAWABLE (channel), 0, 0, gimp_item_get_width (GIMP_ITEM (channel)), gimp_item_get_height (GIMP_ITEM (channel))); }