void gimp_drawable_bucket_fill (GimpDrawable *drawable, GimpFillOptions *options, gboolean fill_transparent, GimpSelectCriterion fill_criterion, gdouble threshold, gboolean sample_merged, gboolean diagonal_neighbors, gdouble seed_x, gdouble seed_y) { GimpImage *image; GeglBuffer *buffer; gdouble mask_x; gdouble mask_y; gint width, height; g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (GIMP_IS_FILL_OPTIONS (options)); image = gimp_item_get_image (GIMP_ITEM (drawable)); gimp_set_busy (image->gimp); buffer = gimp_drawable_get_bucket_fill_buffer (drawable, options, fill_transparent, fill_criterion, threshold, sample_merged, diagonal_neighbors, seed_x, seed_y, NULL, &mask_x, &mask_y, &width, &height); if (buffer) { /* Apply it to the image */ gimp_drawable_apply_buffer (drawable, buffer, GEGL_RECTANGLE (0, 0, width, height), TRUE, C_("undo-type", "Bucket Fill"), gimp_context_get_opacity (GIMP_CONTEXT (options)), gimp_context_get_paint_mode (GIMP_CONTEXT (options)), GIMP_LAYER_COLOR_SPACE_AUTO, GIMP_LAYER_COLOR_SPACE_AUTO, gimp_layer_mode_get_paint_composite_mode ( gimp_context_get_paint_mode (GIMP_CONTEXT (options))), NULL, (gint) mask_x, mask_y); g_object_unref (buffer); gimp_drawable_update (drawable, mask_x, mask_y, width, height); } gimp_unset_busy (image->gimp); }
static void gimp_drawable_edit_fill_direct (GimpDrawable *drawable, GimpFillOptions *options, const gchar *undo_desc) { GeglBuffer *buffer; GimpContext *context; GimpLayerMode mode; gint width; gint height; buffer = gimp_drawable_get_buffer (drawable); context = GIMP_CONTEXT (options); mode = gimp_context_get_paint_mode (context); width = gimp_item_get_width (GIMP_ITEM (drawable)); height = gimp_item_get_height (GIMP_ITEM (drawable)); gimp_drawable_push_undo (drawable, undo_desc, NULL, 0, 0, width, height); if (! gimp_layer_mode_is_subtractive (mode)) gimp_fill_options_fill_buffer (options, drawable, buffer, 0, 0); else gimp_gegl_clear (buffer, NULL); }
static GValueArray * gimp_brush_select_run_callback (GimpPdbDialog *dialog, GimpObject *object, gboolean closing) { GimpBrush *brush = GIMP_BRUSH (object); GimpArray *array; GValueArray *return_vals; array = gimp_array_new (temp_buf_data (brush->mask), brush->mask->width * brush->mask->height * brush->mask->bytes, TRUE); return_vals = gimp_pdb_execute_procedure_by_name (dialog->pdb, dialog->caller_context, NULL, dialog->callback_name, G_TYPE_STRING, object->name, G_TYPE_DOUBLE, gimp_context_get_opacity (dialog->context) * 100.0, GIMP_TYPE_INT32, GIMP_BRUSH_SELECT (dialog)->spacing, GIMP_TYPE_INT32, gimp_context_get_paint_mode (dialog->context), GIMP_TYPE_INT32, brush->mask->width, GIMP_TYPE_INT32, brush->mask->height, GIMP_TYPE_INT32, array->length, GIMP_TYPE_INT8_ARRAY, array, GIMP_TYPE_INT32, closing, G_TYPE_NONE); gimp_array_free (array); return return_vals; }
void gimp_edit_fill (GimpImage *image, GimpDrawable *drawable, GimpFillOptions *options, const gchar *undo_desc) { GeglBuffer *buffer; gint x, y, width, height; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (GIMP_IS_FILL_OPTIONS (options)); if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height)) return; /* nothing to do, but the fill succeeded */ buffer = gimp_fill_options_create_buffer (options, drawable, GEGL_RECTANGLE (0, 0, width, height)); if (! undo_desc) undo_desc = gimp_fill_options_get_undo_desc (options); gimp_drawable_apply_buffer (drawable, buffer, GEGL_RECTANGLE (0, 0, width, height), TRUE, undo_desc, gimp_context_get_opacity (GIMP_CONTEXT (options)), gimp_context_get_paint_mode (GIMP_CONTEXT (options)), NULL, x, y); g_object_unref (buffer); gimp_drawable_update (drawable, x, y, width, height); }
static void gimp_blend_tool_create_image_map (GimpBlendTool *blend_tool, GimpDrawable *drawable) { GimpBlendOptions *options = GIMP_BLEND_TOOL_GET_OPTIONS (blend_tool); GimpContext *context = GIMP_CONTEXT (options); if (! blend_tool->graph) gimp_blend_tool_create_graph (blend_tool); blend_tool->image_map = gimp_image_map_new (drawable, C_("undo-type", "Blend"), blend_tool->graph, GIMP_STOCK_TOOL_BLEND); gimp_image_map_set_region (blend_tool->image_map, GIMP_IMAGE_MAP_REGION_DRAWABLE); g_signal_connect (blend_tool->image_map, "flush", G_CALLBACK (gimp_blend_tool_image_map_flush), blend_tool); gimp_image_map_set_mode (blend_tool->image_map, gimp_context_get_opacity (context), gimp_context_get_paint_mode (context)); }
static void gimp_blend_tool_options_notify (GimpTool *tool, GimpToolOptions *options, const GParamSpec *pspec) { GimpContext *context = GIMP_CONTEXT (options); GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool); if (! strcmp (pspec->name, "gradient")) { gimp_blend_tool_set_gradient (blend_tool, context->gradient); if (blend_tool->filter) gimp_drawable_filter_apply (blend_tool->filter, NULL); } else if (blend_tool->render_node && gegl_node_find_property (blend_tool->render_node, pspec->name)) { /* Sync any property changes on the config object that match the op */ GValue value = G_VALUE_INIT; g_value_init (&value, pspec->value_type); g_object_get_property (G_OBJECT (options), pspec->name, &value); gegl_node_set_property (blend_tool->render_node, pspec->name, &value); g_value_unset (&value); if (! strcmp (pspec->name, "gradient-type")) { if (gimp_blend_tool_is_shapeburst (blend_tool)) gimp_blend_tool_precalc_shapeburst (blend_tool); gimp_blend_tool_update_graph (blend_tool); } gimp_drawable_filter_apply (blend_tool->filter, NULL); } else if (blend_tool->filter && ! strcmp (pspec->name, "opacity")) { gimp_drawable_filter_set_opacity (blend_tool->filter, gimp_context_get_opacity (context)); } else if (blend_tool->filter && ! strcmp (pspec->name, "paint-mode")) { gimp_drawable_filter_set_mode (blend_tool->filter, gimp_context_get_paint_mode (context)); } }
static gboolean gimp_drawable_edit_can_fill_direct (GimpDrawable *drawable, GimpFillOptions *options) { GimpImage *image; GimpContext *context; gdouble opacity; GimpComponentMask affect; GimpLayerMode mode; GimpLayerCompositeMode composite_mode; GimpLayerCompositeRegion composite_region; image = gimp_item_get_image (GIMP_ITEM (drawable)); context = GIMP_CONTEXT (options); opacity = gimp_context_get_opacity (context); affect = gimp_drawable_get_active_mask (drawable); mode = gimp_context_get_paint_mode (context); composite_mode = gimp_layer_mode_get_paint_composite_mode (mode); composite_region = gimp_layer_mode_get_included_region (mode, composite_mode); if (gimp_channel_is_empty (gimp_image_get_mask (image)) && opacity == GIMP_OPACITY_OPAQUE && affect == GIMP_COMPONENT_MASK_ALL && gimp_layer_mode_is_trivial (mode) && (! gimp_layer_mode_is_subtractive (mode) ^ ! (composite_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE))) { switch (gimp_fill_options_get_style (options)) { case GIMP_FILL_STYLE_SOLID: return TRUE; case GIMP_FILL_STYLE_PATTERN: { GimpPattern *pattern; GimpTempBuf *mask; const Babl *format; pattern = gimp_context_get_pattern (context); mask = gimp_pattern_get_mask (pattern); format = gimp_temp_buf_get_format (mask); return ! babl_format_has_alpha (format); } } } return FALSE; }
gboolean gimp_edit_fade (GimpImage *image, GimpContext *context) { GimpDrawableUndo *undo; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (GIMP_IS_CONTEXT (context), FALSE); undo = GIMP_DRAWABLE_UNDO (gimp_image_undo_get_fadeable (image)); if (undo && undo->applied_buffer) { GimpDrawable *drawable; GeglBuffer *buffer; drawable = GIMP_DRAWABLE (GIMP_ITEM_UNDO (undo)->item); g_object_ref (undo); buffer = g_object_ref (undo->applied_buffer); gimp_image_undo (image); gimp_drawable_apply_buffer (drawable, buffer, GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (undo->buffer), gegl_buffer_get_height (undo->buffer)), TRUE, gimp_object_get_name (undo), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), GIMP_LAYER_COLOR_SPACE_AUTO, GIMP_LAYER_COLOR_SPACE_AUTO, GIMP_LAYER_COMPOSITE_AUTO, NULL, undo->x, undo->y); g_object_unref (buffer); g_object_unref (undo); return TRUE; } return FALSE; }
static void gimp_blend_tool_commit (GimpBlendTool *blend_tool) { GimpTool *tool = GIMP_TOOL (blend_tool); GimpBlendOptions *options = GIMP_BLEND_TOOL_GET_OPTIONS (tool); GimpPaintOptions *paint_options = GIMP_PAINT_OPTIONS (options); GimpContext *context = GIMP_CONTEXT (options); GimpImage *image = gimp_display_get_image (tool->display); GimpDrawable *drawable = gimp_image_get_active_drawable (image); GimpProgress *progress; gint off_x; gint off_y; progress = gimp_progress_start (GIMP_PROGRESS (tool), FALSE, _("Blending")); gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); gimp_drawable_blend (drawable, context, gimp_context_get_gradient (context), gimp_context_get_paint_mode (context), options->gradient_type, gimp_context_get_opacity (context), options->offset, paint_options->gradient_options->gradient_repeat, paint_options->gradient_options->gradient_reverse, options->supersample, options->supersample_depth, options->supersample_threshold, options->dither, blend_tool->start_x - off_x, blend_tool->start_y - off_y, blend_tool->end_x - off_x, blend_tool->end_y - off_y, progress); if (progress) gimp_progress_end (progress); gimp_image_flush (image); }
void context_paint_mode_cmd_callback (GtkAction *action, gint value, gpointer data) { GimpContext *context; GimpToolInfo *tool_info; GimpLayerModeEffects paint_mode; gint index; return_if_no_context (context, data); paint_mode = gimp_context_get_paint_mode (context); index = action_select_value ((GimpActionSelectType) value, context_paint_mode_index (paint_mode), 0, G_N_ELEMENTS (paint_modes) - 1, 0, 0.0, 1.0, 1.0, 0.0, FALSE); gimp_context_set_paint_mode (context, paint_modes[index]); tool_info = gimp_context_get_tool (context); if (tool_info && GIMP_IS_TOOL_OPTIONS (tool_info->tool_options)) { GimpDisplay *display; const char *value_desc; gimp_enum_get_value (GIMP_TYPE_LAYER_MODE_EFFECTS, index, NULL, NULL, &value_desc, NULL); display = action_data_get_display (data); if (value_desc && display) { action_message (display, G_OBJECT (tool_info->tool_options), _("Paint Mode: %s"), value_desc); } } }
static void gimp_clone_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gdouble opacity, GimpPickable *src_pickable, GeglBuffer *src_buffer, 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) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpCloneOptions *options = GIMP_CLONE_OPTIONS (paint_options); GimpSourceOptions *source_options = GIMP_SOURCE_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); gdouble fade_point; gdouble force; if (gimp_source_core_use_source (source_core, source_options)) { gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (src_rect->x, src_rect->y, paint_area_width, paint_area_height), paint_buffer, GEGL_RECTANGLE (paint_area_offset_x, paint_area_offset_y, 0, 0)); } else if (options->clone_type == GIMP_PATTERN_CLONE) { GimpPattern *pattern = gimp_context_get_pattern (context); GeglBuffer *src_buffer = gimp_pattern_create_buffer (pattern); gegl_buffer_set_pattern (paint_buffer, GEGL_RECTANGLE (paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height), src_buffer, - paint_buffer_x - src_offset_x, - paint_buffer_y - src_offset_y); g_object_unref (src_buffer); } else { g_return_if_reached (); } fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); force = gimp_dynamics_get_linear_value (GIMP_BRUSH_CORE (paint_core)->dynamics, GIMP_DYNAMICS_OUTPUT_FORCE, coords, paint_options, fade_point); gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), force, /* In fixed mode, paint incremental so the * individual brushes are properly applied * on top of each other. * Otherwise the stuff we paint is seamless * and we don't need intermediate masking. */ source_options->align_mode == GIMP_SOURCE_ALIGN_FIXED ? GIMP_PAINT_INCREMENTAL : GIMP_PAINT_CONSTANT); }
void gimp_edit_fill (GimpImage *image, GimpDrawable *drawable, GimpFillOptions *options, const gchar *undo_desc) { GeglBuffer *dest_buffer; GimpPattern *pattern = NULL; GimpRGB color; const Babl *format; gint x, y, width, height; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (GIMP_IS_FILL_OPTIONS (options)); if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height)) return; /* nothing to do, but the fill succeeded */ switch (gimp_fill_options_get_style (options)) { case GIMP_FILL_STYLE_SOLID: gimp_context_get_foreground (GIMP_CONTEXT (options), &color); break; case GIMP_FILL_STYLE_PATTERN: pattern = gimp_context_get_pattern (GIMP_CONTEXT (options)); break; } if (pattern && babl_format_has_alpha (gimp_temp_buf_get_format (pattern->mask)) && ! gimp_drawable_has_alpha (drawable)) { format = gimp_drawable_get_format_with_alpha (drawable); } else { format = gimp_drawable_get_format (drawable); } dest_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height), format); if (pattern) { GeglBuffer *src_buffer = gimp_pattern_create_buffer (pattern); gegl_buffer_set_pattern (dest_buffer, NULL, src_buffer, 0, 0); g_object_unref (src_buffer); } else { GeglColor *gegl_color = gimp_gegl_color_new (&color); gegl_buffer_set_color (dest_buffer, NULL, gegl_color); g_object_unref (gegl_color); } if (! undo_desc) undo_desc = gimp_fill_options_get_undo_desc (options); gimp_drawable_apply_buffer (drawable, dest_buffer, GEGL_RECTANGLE (0, 0, width, height), TRUE, undo_desc, gimp_context_get_opacity (GIMP_CONTEXT (options)), gimp_context_get_paint_mode (GIMP_CONTEXT (options)), NULL, x, y); g_object_unref (dest_buffer); gimp_drawable_update (drawable, x, y, width, height); }
static void gimp_bucket_fill_tool_button_release (GimpTool *tool, const GimpCoords *coords, guint32 time, GdkModifierType state, GimpButtonReleaseType release_type, GimpDisplay *display) { GimpBucketFillOptions *options = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (tool); GimpImage *image = gimp_display_get_image (display); if ((release_type == GIMP_BUTTON_RELEASE_CLICK || release_type == GIMP_BUTTON_RELEASE_NO_MOTION) && gimp_image_coords_in_active_pickable (image, coords, options->sample_merged, TRUE)) { GimpDrawable *drawable = gimp_image_get_active_drawable (image); GimpContext *context = GIMP_CONTEXT (options); gint x, y; GError *error = NULL; x = coords->x; y = coords->y; if (! options->sample_merged) { gint off_x, off_y; gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); x -= off_x; y -= off_y; } if (! gimp_drawable_bucket_fill (drawable, context, options->fill_mode, gimp_context_get_paint_mode (context), gimp_context_get_opacity (context), ! options->fill_selection, options->fill_transparent, options->fill_criterion, options->threshold, options->sample_merged, x, y, &error)) { gimp_message_literal (display->gimp, G_OBJECT (display), GIMP_MESSAGE_WARNING, error->message); g_clear_error (&error); } else { gimp_image_flush (image); } } GIMP_TOOL_CLASS (parent_class)->button_release (tool, coords, time, state, release_type, display); tool->display = NULL; tool->drawable = NULL; }
void _gimp_paintbrush_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, gdouble opacity) { GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); GimpContext *context = GIMP_CONTEXT (paint_options); GimpPressureOptions *pressure_options = paint_options->pressure_options; GimpImage *image; GimpRGB gradient_color; TempBuf *area; guchar col[MAX_CHANNELS]; GimpPaintApplicationMode paint_appl_mode; image = gimp_item_get_image (GIMP_ITEM (drawable)); opacity *= gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); if (opacity == 0.0) return; paint_appl_mode = paint_options->application_mode; area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); if (! area) return; /* optionally take the color from the current gradient */ if (gimp_paint_options_get_gradient_color (paint_options, image, paint_core->cur_coords.pressure, paint_core->pixel_dist, &gradient_color)) { opacity *= gradient_color.a; gimp_rgb_get_uchar (&gradient_color, &col[RED_PIX], &col[GREEN_PIX], &col[BLUE_PIX]); col[ALPHA_PIX] = OPAQUE_OPACITY; color_pixels (temp_buf_data (area), col, area->width * area->height, area->bytes); paint_appl_mode = GIMP_PAINT_INCREMENTAL; } /* otherwise check if the brush has a pixmap and use that to color the area */ else if (brush_core->brush && brush_core->brush->pixmap) { gimp_brush_core_color_area_with_pixmap (brush_core, drawable, area, gimp_paint_options_get_brush_mode (paint_options)); paint_appl_mode = GIMP_PAINT_INCREMENTAL; } /* otherwise fill the area with the foreground color */ else { gimp_image_get_foreground (image, context, gimp_drawable_type (drawable), col); col[area->bytes - 1] = OPAQUE_OPACITY; color_pixels (temp_buf_data (area), col, area->width * area->height, area->bytes); } if (paint_core->use_pressure && pressure_options->opacity) opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure; /* finally, let the brush core paste the colored area on the canvas */ gimp_brush_core_paste_canvas (brush_core, drawable, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), paint_appl_mode); }
static GObject * gimp_brush_select_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObject *object; GimpPdbDialog *dialog; GimpBrushSelect *select; GtkWidget *table; GtkAdjustment *spacing_adj; object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); dialog = GIMP_PDB_DIALOG (object); select = GIMP_BRUSH_SELECT (object); gimp_context_set_opacity (dialog->context, select->initial_opacity); gimp_context_set_paint_mode (dialog->context, select->initial_mode); g_signal_connect (dialog->context, "opacity-changed", G_CALLBACK (gimp_brush_select_opacity_changed), dialog); g_signal_connect (dialog->context, "paint-mode-changed", G_CALLBACK (gimp_brush_select_mode_changed), dialog); dialog->view = gimp_brush_factory_view_new (GIMP_VIEW_TYPE_GRID, dialog->context->gimp->brush_factory, dialog->context, FALSE, GIMP_VIEW_SIZE_MEDIUM, 1, dialog->menu_factory); gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (GIMP_CONTAINER_EDITOR (dialog->view)->view), 5 * (GIMP_VIEW_SIZE_MEDIUM + 2), 5 * (GIMP_VIEW_SIZE_MEDIUM + 2)); gtk_container_set_border_width (GTK_CONTAINER (dialog->view), 12); gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), dialog->view); gtk_widget_show (dialog->view); /* Create the frame and the table for the options */ table = GIMP_BRUSH_FACTORY_VIEW (dialog->view)->spacing_scale->parent; gtk_table_set_col_spacings (GTK_TABLE (table), 6); gtk_table_set_row_spacings (GTK_TABLE (table), 2); /* Create the opacity scale widget */ select->opacity_data = GTK_ADJUSTMENT (gimp_scale_entry_new (GTK_TABLE (table), 0, 1, _("Opacity:"), -1, 5, gimp_context_get_opacity (dialog->context) * 100.0, 0.0, 100.0, 1.0, 10.0, 1, TRUE, 0.0, 0.0, NULL, NULL)); g_signal_connect (select->opacity_data, "value-changed", G_CALLBACK (gimp_brush_select_opacity_update), select); /* Create the paint mode option menu */ select->paint_mode_menu = gimp_paint_mode_menu_new (TRUE, FALSE); gimp_table_attach_aligned (GTK_TABLE (table), 0, 2, _("Mode:"), 0.0, 0.5, select->paint_mode_menu, 2, FALSE); gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (select->paint_mode_menu), gimp_context_get_paint_mode (dialog->context), G_CALLBACK (gimp_brush_select_mode_update), select); spacing_adj = GIMP_BRUSH_FACTORY_VIEW (dialog->view)->spacing_adjustment; /* Use passed spacing instead of brushes default */ if (select->spacing >= 0) gtk_adjustment_set_value (spacing_adj, select->spacing); g_signal_connect (spacing_adj, "value-changed", G_CALLBACK (gimp_brush_select_spacing_update), select); gtk_widget_show (table); return object; }
void gimp_drawable_bucket_fill (GimpDrawable *drawable, GimpFillOptions *options, gboolean fill_transparent, GimpSelectCriterion fill_criterion, gdouble threshold, gboolean sample_merged, gboolean diagonal_neighbors, gdouble seed_x, gdouble seed_y) { GimpImage *image; GimpPickable *pickable; GeglBuffer *buffer; GeglBuffer *mask_buffer; gboolean antialias; gint x, y, width, height; gint mask_offset_x = 0; gint mask_offset_y = 0; gint sel_x, sel_y, sel_width, sel_height; g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (GIMP_IS_FILL_OPTIONS (options)); image = gimp_item_get_image (GIMP_ITEM (drawable)); if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &sel_x, &sel_y, &sel_width, &sel_height)) return; gimp_set_busy (image->gimp); if (sample_merged) pickable = GIMP_PICKABLE (image); else pickable = GIMP_PICKABLE (drawable); antialias = gimp_fill_options_get_antialias (options); /* Do a seed bucket fill...To do this, calculate a new * contiguous region. */ mask_buffer = gimp_pickable_contiguous_region_by_seed (pickable, antialias, threshold, fill_transparent, fill_criterion, diagonal_neighbors, (gint) seed_x, (gint) seed_y); gimp_gegl_mask_bounds (mask_buffer, &x, &y, &width, &height); width -= x; height -= y; /* If there is a selection, inersect the region bounds * with the selection bounds, to avoid processing areas * that are going to be masked out anyway. The actual * intersection of the fill region with the mask data * happens when combining the fill buffer, in * gimp_drawable_apply_buffer(). */ if (! gimp_channel_is_empty (gimp_image_get_mask (image))) { gint off_x = 0; gint off_y = 0; if (sample_merged) gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); if (! gimp_rectangle_intersect (x, y, width, height, sel_x + off_x, sel_y + off_y, sel_width, sel_height, &x, &y, &width, &height)) { /* The fill region and the selection are disjoint; bail. */ g_object_unref (mask_buffer); gimp_unset_busy (image->gimp); return; } } /* make sure we handle the mask correctly if it was sample-merged */ if (sample_merged) { GimpItem *item = GIMP_ITEM (drawable); gint off_x, off_y; /* Limit the channel bounds to the drawable's extents */ gimp_item_get_offset (item, &off_x, &off_y); gimp_rectangle_intersect (x, y, width, height, off_x, off_y, gimp_item_get_width (item), gimp_item_get_height (item), &x, &y, &width, &height); mask_offset_x = x; mask_offset_y = y; /* translate mask bounds to drawable coords */ x -= off_x; y -= off_y; } else { mask_offset_x = x; mask_offset_y = y; } buffer = gimp_fill_options_create_buffer (options, drawable, GEGL_RECTANGLE (0, 0, width, height)); gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer, mask_buffer, -mask_offset_x, -mask_offset_y, 1.0); g_object_unref (mask_buffer); /* Apply it to the image */ gimp_drawable_apply_buffer (drawable, buffer, GEGL_RECTANGLE (0, 0, width, height), TRUE, C_("undo-type", "Bucket Fill"), gimp_context_get_opacity (GIMP_CONTEXT (options)), gimp_context_get_paint_mode (GIMP_CONTEXT (options)), NULL, x, y); g_object_unref (buffer); gimp_drawable_update (drawable, x, y, width, height); gimp_unset_busy (image->gimp); }
static void gimp_drawable_stroke_scan_convert (GimpDrawable *drawable, GimpStrokeOptions *options, GimpScanConvert *scan_convert) { GimpContext *context = GIMP_CONTEXT (options); GimpImage *image; gdouble width; TileManager *base; TileManager *mask; gint x, y, w, h; gint bytes; gint off_x, off_y; guchar bg[1] = { 0, }; PixelRegion maskPR, basePR; image = gimp_item_get_image (GIMP_ITEM (drawable)); /* must call gimp_channel_is_empty() instead of relying on * gimp_drawable_mask_intersect() because the selection pretends to * be empty while it is being stroked, to prevent masking itself. */ if (gimp_channel_is_empty (gimp_image_get_mask (image))) { x = 0; y = 0; w = gimp_item_width (GIMP_ITEM (drawable)); h = gimp_item_height (GIMP_ITEM (drawable)); } else if (! gimp_drawable_mask_intersect (drawable, &x, &y, &w, &h)) { return; } gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y); width = options->width; if (options->unit != GIMP_UNIT_PIXEL) { gimp_scan_convert_set_pixel_ratio (scan_convert, image->yresolution / image->xresolution); width *= (image->yresolution / _gimp_unit_get_factor (image->gimp, options->unit)); } gimp_scan_convert_stroke (scan_convert, width, options->join_style, options->cap_style, options->miter_limit, options->dash_offset, options->dash_info); /* fill a 1-bpp Tilemanager with black, this will describe the shape * of the stroke. */ mask = tile_manager_new (w, h, 1); pixel_region_init (&maskPR, mask, 0, 0, w, h, TRUE); color_region (&maskPR, bg); /* render the stroke into it */ gimp_scan_convert_render (scan_convert, mask, x + off_x, y + off_y, options->antialias); bytes = gimp_drawable_bytes_with_alpha (drawable); base = tile_manager_new (w, h, bytes); pixel_region_init (&basePR, base, 0, 0, w, h, TRUE); pixel_region_init (&maskPR, mask, 0, 0, w, h, FALSE); switch (options->style) { case GIMP_STROKE_STYLE_SOLID: { guchar tmp_col[MAX_CHANNELS] = { 0, }; guchar col[MAX_CHANNELS] = { 0, }; gimp_rgb_get_uchar (&context->foreground, &tmp_col[RED_PIX], &tmp_col[GREEN_PIX], &tmp_col[BLUE_PIX]); gimp_image_transform_color (image, gimp_drawable_type (drawable), col, GIMP_RGB, tmp_col); col[bytes - 1] = OPAQUE_OPACITY; color_region_mask (&basePR, &maskPR, col); } break; case GIMP_STROKE_STYLE_PATTERN: { GimpPattern *pattern; TempBuf *pat_buf; gboolean new_buf; pattern = gimp_context_get_pattern (context); pat_buf = gimp_image_transform_temp_buf (image, gimp_drawable_type (drawable), pattern->mask, &new_buf); pattern_region (&basePR, &maskPR, pat_buf, x, y); if (new_buf) temp_buf_free (pat_buf); } break; } /* Apply to drawable */ pixel_region_init (&basePR, base, 0, 0, w, h, FALSE); gimp_drawable_apply_region (drawable, &basePR, TRUE, _("Render Stroke"), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), NULL, x, y); tile_manager_unref (mask); tile_manager_unref (base); gimp_drawable_update (drawable, x, y, w, h); }
void _gimp_paintbrush_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gdouble opacity) { GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_core); GimpContext *context = GIMP_CONTEXT (paint_options); GimpDynamics *dynamics = brush_core->dynamics; GimpImage *image; GimpRGB gradient_color; GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; GimpPaintApplicationMode paint_appl_mode; gdouble fade_point; gdouble grad_point; gdouble force; gdouble dyn_force; GimpDynamicsOutput *dyn_output = NULL; image = gimp_item_get_image (GIMP_ITEM (drawable)); 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; 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_appl_mode = paint_options->application_mode; grad_point = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_COLOR, coords, paint_options, fade_point); if (gimp_paint_options_get_gradient_color (paint_options, image, grad_point, paint_core->pixel_dist, &gradient_color)) { /* optionally take the color from the current gradient */ GeglColor *color; opacity *= gradient_color.a; gimp_rgb_set_alpha (&gradient_color, GIMP_OPACITY_OPAQUE); color = gimp_gegl_color_new (&gradient_color); gegl_buffer_set_color (paint_buffer, NULL, color); g_object_unref (color); paint_appl_mode = GIMP_PAINT_INCREMENTAL; } else if (brush_core->brush && gimp_brush_get_pixmap (brush_core->brush)) { /* otherwise check if the brush has a pixmap and use that to * color the area */ gimp_brush_core_color_area_with_pixmap (brush_core, drawable, coords, paint_buffer, paint_buffer_x, paint_buffer_y, gimp_paint_options_get_brush_mode (paint_options)); paint_appl_mode = GIMP_PAINT_INCREMENTAL; } else { /* otherwise fill the area with the foreground color */ GimpRGB foreground; GeglColor *color; gimp_context_get_foreground (context, &foreground); color = gimp_gegl_color_new (&foreground); gegl_buffer_set_color (paint_buffer, NULL, color); g_object_unref (color); } dyn_output = gimp_dynamics_get_output (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE); dyn_force = gimp_dynamics_get_linear_value (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE, coords, paint_options, fade_point); if (gimp_dynamics_output_is_enabled (dyn_output)) force = dyn_force; else force = paint_options->brush_force; /* finally, let the brush core paste the colored area on the canvas */ gimp_brush_core_paste_canvas (brush_core, drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), force, paint_appl_mode); }
static void gimp_ink_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, guint32 time) { GimpInk *ink = GIMP_INK (paint_core); GimpInkOptions *options = GIMP_INK_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpBlob *blob_union = NULL; GimpBlob *blob_to_render; GeglBuffer *paint_buffer; gint paint_buffer_x; gint paint_buffer_y; GimpRGB foreground; GeglColor *color; if (! ink->last_blob) { ink->last_blob = ink_pen_ellipse (options, coords->x, coords->y, coords->pressure, coords->xtilt, coords->ytilt, 100); if (ink->start_blob) g_free (ink->start_blob); ink->start_blob = gimp_blob_duplicate (ink->last_blob); blob_to_render = ink->last_blob; } else { GimpBlob *blob = ink_pen_ellipse (options, coords->x, coords->y, coords->pressure, coords->xtilt, coords->ytilt, coords->velocity * 100); blob_union = gimp_blob_convex_union (ink->last_blob, blob); g_free (ink->last_blob); ink->last_blob = blob; blob_to_render = blob_union; } /* Get the buffer */ ink->cur_blob = blob_to_render; paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable, paint_options, coords, &paint_buffer_x, &paint_buffer_y); ink->cur_blob = NULL; if (! paint_buffer) return; gimp_context_get_foreground (context, &foreground); color = gimp_gegl_color_new (&foreground); gegl_buffer_set_color (paint_buffer, NULL, color); g_object_unref (color); /* draw the blob directly to the canvas_buffer */ render_blob (paint_core->canvas_buffer, GEGL_RECTANGLE (paint_core->paint_buffer_x, paint_core->paint_buffer_y, gegl_buffer_get_width (paint_core->paint_buffer), gegl_buffer_get_height (paint_core->paint_buffer)), blob_to_render); /* draw the paint_area using the just rendered canvas_buffer as mask */ gimp_paint_core_paste (paint_core, paint_core->canvas_buffer, GEGL_RECTANGLE (paint_core->paint_buffer_x, paint_core->paint_buffer_y, gegl_buffer_get_width (paint_core->paint_buffer), gegl_buffer_get_height (paint_core->paint_buffer)), drawable, GIMP_OPACITY_OPAQUE, gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), GIMP_PAINT_CONSTANT); if (blob_union) g_free (blob_union); }
static void gimp_blend_tool_button_release (GimpTool *tool, const GimpCoords *coords, guint32 time, GdkModifierType state, GimpButtonReleaseType release_type, GimpDisplay *display) { GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool); GimpBlendOptions *options = GIMP_BLEND_TOOL_GET_OPTIONS (tool); GimpPaintOptions *paint_options = GIMP_PAINT_OPTIONS (options); GimpContext *context = GIMP_CONTEXT (options); GimpImage *image = gimp_display_get_image (display); gimp_tool_pop_status (tool, display); gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool)); gimp_tool_control_halt (tool->control); if ((release_type != GIMP_BUTTON_RELEASE_CANCEL) && ((blend_tool->start_x != blend_tool->end_x) || (blend_tool->start_y != blend_tool->end_y))) { GimpDrawable *drawable = gimp_image_get_active_drawable (image); GimpProgress *progress; gint off_x; gint off_y; progress = gimp_progress_start (GIMP_PROGRESS (tool), _("Blending"), FALSE); gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); gimp_drawable_blend (drawable, context, GIMP_CUSTOM_MODE, gimp_context_get_paint_mode (context), options->gradient_type, gimp_context_get_opacity (context), options->offset, paint_options->gradient_options->gradient_repeat, paint_options->gradient_options->gradient_reverse, options->supersample, options->supersample_depth, options->supersample_threshold, options->dither, blend_tool->start_x - off_x, blend_tool->start_y - off_y, blend_tool->end_x - off_x, blend_tool->end_y - off_y, progress); if (progress) gimp_progress_end (progress); gimp_image_flush (image); } tool->display = NULL; tool->drawable = NULL; }
static void gimp_ink_motion (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, guint32 time) { GimpInk *ink = GIMP_INK (paint_core); GimpInkOptions *options = GIMP_INK_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image; GimpBlob *blob_union = NULL; GimpBlob *blob_to_render; TempBuf *area; guchar col[MAX_CHANNELS]; PixelRegion blob_maskPR; image = gimp_item_get_image (GIMP_ITEM (drawable)); if (! ink->last_blob) { ink->last_blob = ink_pen_ellipse (options, coords->x, coords->y, coords->pressure, coords->xtilt, coords->ytilt, 100); if (ink->start_blob) g_free (ink->start_blob); ink->start_blob = gimp_blob_duplicate (ink->last_blob); blob_to_render = ink->last_blob; } else { GimpBlob *blob = ink_pen_ellipse (options, coords->x, coords->y, coords->pressure, coords->xtilt, coords->ytilt, coords->velocity * 100); blob_union = gimp_blob_convex_union (ink->last_blob, blob); g_free (ink->last_blob); ink->last_blob = blob; blob_to_render = blob_union; } /* Get the buffer */ ink->cur_blob = blob_to_render; area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options, coords); ink->cur_blob = NULL; if (! area) return; gimp_image_get_foreground (image, context, gimp_drawable_type (drawable), col); /* set the alpha channel */ col[paint_core->canvas_buf->bytes - 1] = OPAQUE_OPACITY; /* color the pixels */ color_pixels (temp_buf_get_data (paint_core->canvas_buf), col, area->width * area->height, area->bytes); gimp_paint_core_validate_canvas_tiles (paint_core, paint_core->canvas_buf->x, paint_core->canvas_buf->y, paint_core->canvas_buf->width, paint_core->canvas_buf->height); /* draw the blob directly to the canvas_tiles */ pixel_region_init (&blob_maskPR, paint_core->canvas_tiles, paint_core->canvas_buf->x, paint_core->canvas_buf->y, paint_core->canvas_buf->width, paint_core->canvas_buf->height, TRUE); render_blob (blob_to_render, &blob_maskPR); /* draw the canvas_buf using the just rendered canvas_tiles as mask */ pixel_region_init (&blob_maskPR, paint_core->canvas_tiles, paint_core->canvas_buf->x, paint_core->canvas_buf->y, paint_core->canvas_buf->width, paint_core->canvas_buf->height, FALSE); gimp_paint_core_paste (paint_core, &blob_maskPR, drawable, GIMP_OPACITY_OPAQUE, gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), GIMP_PAINT_CONSTANT); if (blob_union) g_free (blob_union); }
static void gimp_clone_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, gdouble opacity, GimpPickable *src_pickable, PixelRegion *srcPR, gint src_offset_x, gint src_offset_y, TempBuf *paint_area, gint paint_area_offset_x, gint paint_area_offset_y, gint paint_area_width, gint paint_area_height) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpCloneOptions *options = GIMP_CLONE_OPTIONS (paint_options); GimpSourceOptions *source_options = GIMP_SOURCE_OPTIONS (paint_options); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); GimpImage *src_image = NULL; GimpDynamicsOutput *force_output; GimpImageType src_type = 0; GimpImageType dest_type; gpointer pr = NULL; gint y; PixelRegion destPR; GimpPattern *pattern = NULL; gdouble fade_point; gdouble force; switch (options->clone_type) { case GIMP_IMAGE_CLONE: src_image = gimp_pickable_get_image (src_pickable); src_type = gimp_pickable_get_image_type (src_pickable); if (gimp_pickable_get_bytes (src_pickable) < srcPR->bytes) src_type = GIMP_IMAGE_TYPE_WITH_ALPHA (src_type); pixel_region_init_temp_buf (&destPR, paint_area, paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height); pr = pixel_regions_register (2, srcPR, &destPR); break; case GIMP_PATTERN_CLONE: pattern = gimp_context_get_pattern (context); pixel_region_init_temp_buf (&destPR, paint_area, 0, 0, paint_area->width, paint_area->height); pr = pixel_regions_register (1, &destPR); break; } dest_type = gimp_drawable_type (drawable); for (; pr != NULL; pr = pixel_regions_process (pr)) { guchar *s = srcPR->data; guchar *d = destPR.data; for (y = 0; y < destPR.h; y++) { switch (options->clone_type) { case GIMP_IMAGE_CLONE: gimp_clone_line_image (image, dest_type, src_image, src_type, s, d, srcPR->bytes, destPR.bytes, destPR.w); s += srcPR->rowstride; break; case GIMP_PATTERN_CLONE: gimp_clone_line_pattern (image, dest_type, pattern, d, paint_area->x + src_offset_x, paint_area->y + y + src_offset_y, destPR.bytes, destPR.w); break; } d += destPR.rowstride; } } force_output = gimp_dynamics_get_output (GIMP_BRUSH_CORE (paint_core)->dynamics, GIMP_DYNAMICS_OUTPUT_FORCE); fade_point = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); force = gimp_dynamics_output_get_linear_value (force_output, coords, paint_options, fade_point); gimp_brush_core_paste_canvas (GIMP_BRUSH_CORE (paint_core), drawable, coords, MIN (opacity, GIMP_OPACITY_OPAQUE), gimp_context_get_opacity (context), gimp_context_get_paint_mode (context), gimp_paint_options_get_brush_mode (paint_options), force, /* In fixed mode, paint incremental so the * individual brushes are properly applied * on top of each other. * Otherwise the stuff we paint is seamless * and we don't need intermediate masking. */ source_options->align_mode == GIMP_SOURCE_ALIGN_FIXED ? GIMP_PAINT_INCREMENTAL : GIMP_PAINT_CONSTANT); }
void gimp_drawable_edit_fill (GimpDrawable *drawable, GimpFillOptions *options, const gchar *undo_desc) { GimpContext *context; gint x, y, width, height; g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (GIMP_IS_FILL_OPTIONS (options)); if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height)) { return; /* nothing to do, but the fill succeeded */ } context = GIMP_CONTEXT (options); if (gimp_layer_mode_is_alpha_only (gimp_context_get_paint_mode (context))) { if (! gimp_drawable_has_alpha (drawable) || ! (gimp_drawable_get_active_mask (drawable) & GIMP_COMPONENT_MASK_ALPHA)) { return; /* nothing to do, but the fill succeeded */ } } if (! undo_desc) undo_desc = gimp_fill_options_get_undo_desc (options); /* check if we can fill the drawable's buffer directly */ if (gimp_drawable_edit_can_fill_direct (drawable, options)) { gimp_drawable_edit_fill_direct (drawable, options, undo_desc); gimp_drawable_update (drawable, x, y, width, height); } else { GeglNode *operation; GimpDrawableFilter *filter; gdouble opacity; GimpLayerMode mode; GimpLayerMode composite_mode; opacity = gimp_context_get_opacity (context); mode = gimp_context_get_paint_mode (context); composite_mode = gimp_layer_mode_get_paint_composite_mode (mode); operation = gegl_node_new_child (NULL, "operation", "gimp:fill-source", "options", options, "drawable", drawable, "pattern-offset-x", -x, "pattern-offset-y", -y, NULL); filter = gimp_drawable_filter_new (drawable, undo_desc, operation, NULL); gimp_drawable_filter_set_opacity (filter, opacity); gimp_drawable_filter_set_mode (filter, mode, GIMP_LAYER_COLOR_SPACE_AUTO, GIMP_LAYER_COLOR_SPACE_AUTO, composite_mode); gimp_drawable_filter_apply (filter, NULL); gimp_drawable_filter_commit (filter, NULL, FALSE); g_object_unref (filter); g_object_unref (operation); } }