static void gimp_drawable_mod_undo_constructed (GObject *object) { GimpDrawableModUndo *drawable_mod_undo = GIMP_DRAWABLE_MOD_UNDO (object); GimpItem *item; GimpDrawable *drawable; G_OBJECT_CLASS (parent_class)->constructed (object); g_assert (GIMP_IS_DRAWABLE (GIMP_ITEM_UNDO (object)->item)); item = GIMP_ITEM_UNDO (object)->item; drawable = GIMP_DRAWABLE (item); if (drawable_mod_undo->copy_buffer) { drawable_mod_undo->buffer = gegl_buffer_dup (gimp_drawable_get_buffer (drawable)); } else { drawable_mod_undo->buffer = g_object_ref (gimp_drawable_get_buffer (drawable)); } gimp_item_get_offset (item, &drawable_mod_undo->offset_x, &drawable_mod_undo->offset_y); }
void gimp_channel_combine_buffer (GimpChannel *mask, GeglBuffer *add_on_buffer, GimpChannelOps op, gint off_x, gint off_y) { GimpChannelCombineData data; g_return_if_fail (GIMP_IS_CHANNEL (mask)); g_return_if_fail (GEGL_IS_BUFFER (add_on_buffer)); if (gimp_channel_combine_start (mask, op, GEGL_RECTANGLE ( off_x, off_y, gegl_buffer_get_width (add_on_buffer), gegl_buffer_get_height (add_on_buffer)), FALSE, FALSE, &data)) { GeglBuffer *buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); gimp_gegl_mask_combine_buffer (buffer, add_on_buffer, op, off_x, off_y); } gimp_channel_combine_end (mask, &data); }
static void gimp_text_layer_render_layout (GimpTextLayer *layer, GimpTextLayout *layout) { GimpDrawable *drawable = GIMP_DRAWABLE (layer); GimpItem *item = GIMP_ITEM (layer); GeglBuffer *buffer; cairo_t *cr; cairo_surface_t *surface; gint width; gint height; g_return_if_fail (gimp_drawable_has_alpha (drawable)); width = gimp_item_get_width (item); height = gimp_item_get_height (item); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); cr = cairo_create (surface); gimp_text_layout_render (layout, cr, layer->text->base_dir, FALSE); cairo_destroy (cr); cairo_surface_flush (surface); buffer = gimp_cairo_surface_create_buffer (surface); gegl_buffer_copy (buffer, NULL, gimp_drawable_get_buffer (drawable), NULL); g_object_unref (buffer); cairo_surface_destroy (surface); gimp_drawable_update (drawable, 0, 0, width, height); }
static void gimp_layer_new_convert_buffer (GimpLayer *layer, GeglBuffer *src_buffer, GimpColorProfile *src_profile, GError **error) { GimpDrawable *drawable = GIMP_DRAWABLE (layer); GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer)); GimpColorConfig *config = image->gimp->config->color_management; GeglBuffer *dest_buffer = gimp_drawable_get_buffer (drawable); GimpColorProfile *dest_profile; dest_profile = gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (layer)); if (! src_profile || ! dest_profile || /* FIXME: this is the wrong check, need something like file import * conversion config */ config->mode == GIMP_COLOR_MANAGEMENT_OFF) { gegl_buffer_copy (src_buffer, NULL, GEGL_ABYSS_NONE, dest_buffer, NULL); return; } gimp_gegl_convert_color_profile (src_buffer, NULL, src_profile, dest_buffer, NULL, dest_profile, GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL, TRUE, NULL); }
static void gimp_image_duplicate_mask (GimpImage *image, GimpImage *new_image) { GimpDrawable *mask; GimpDrawable *new_mask; mask = GIMP_DRAWABLE (gimp_image_get_mask (image)); new_mask = GIMP_DRAWABLE (gimp_image_get_mask (new_image)); gegl_buffer_copy (gimp_drawable_get_buffer (mask), NULL, gimp_drawable_get_buffer (new_mask), NULL); GIMP_CHANNEL (new_mask)->bounds_known = FALSE; GIMP_CHANNEL (new_mask)->boundary_known = FALSE; }
static void gimp_mask_undo_constructed (GObject *object) { GimpMaskUndo *mask_undo = GIMP_MASK_UNDO (object); GimpChannel *channel; GimpDrawable *drawable; gint x1, y1, x2, y2; if (G_OBJECT_CLASS (parent_class)->constructed) G_OBJECT_CLASS (parent_class)->constructed (object); g_assert (GIMP_IS_CHANNEL (GIMP_ITEM_UNDO (object)->item)); channel = GIMP_CHANNEL (GIMP_ITEM_UNDO (object)->item); drawable = GIMP_DRAWABLE (channel); if (gimp_channel_bounds (channel, &x1, &y1, &x2, &y2)) { mask_undo->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), mask_undo->buffer, GEGL_RECTANGLE (0, 0, 0, 0)); mask_undo->x = x1; mask_undo->y = y1; } mask_undo->format = gimp_drawable_get_format (drawable); }
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); }
void gimp_channel_combine_buffer (GimpChannel *mask, GeglBuffer *add_on_buffer, GimpChannelOps op, gint off_x, gint off_y) { GeglBuffer *buffer; gint x, y, w, h; g_return_if_fail (GIMP_IS_CHANNEL (mask)); g_return_if_fail (GEGL_IS_BUFFER (add_on_buffer)); buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); if (! gimp_gegl_mask_combine_buffer (buffer, add_on_buffer, op, off_x, off_y)) return; gimp_rectangle_intersect (off_x, off_y, gegl_buffer_get_width (add_on_buffer), gegl_buffer_get_height (add_on_buffer), 0, 0, gimp_item_get_width (GIMP_ITEM (mask)), gimp_item_get_height (GIMP_ITEM (mask)), &x, &y, &w, &h); mask->bounds_known = FALSE; gimp_drawable_update (GIMP_DRAWABLE (mask), x, y, w, h); }
static gboolean sel2path (gint32 image_ID) { gint32 selection_ID; pixel_outline_list_type olt; spline_list_array_type splines; gimp_selection_bounds (image_ID, &has_sel, &sel_x1, &sel_y1, &sel_x2, &sel_y2); sel_width = sel_x2 - sel_x1; sel_height = sel_y2 - sel_y1; /* Now get the selection channel */ selection_ID = gimp_image_get_selection (image_ID); if (selection_ID < 0) return FALSE; sel_buffer = gimp_drawable_get_buffer (selection_ID); olt = find_outline_pixels (); splines = fitted_splines (olt); do_points (splines, image_ID); g_object_unref (sel_buffer); gimp_displays_flush (); return TRUE; }
static void gimp_drawable_mod_undo_pop (GimpUndo *undo, GimpUndoMode undo_mode, GimpUndoAccumulator *accum) { GimpDrawableModUndo *drawable_mod_undo = GIMP_DRAWABLE_MOD_UNDO (undo); GimpDrawable *drawable = GIMP_DRAWABLE (GIMP_ITEM_UNDO (undo)->item); GeglBuffer *buffer; gint offset_x; gint offset_y; GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum); buffer = drawable_mod_undo->buffer; offset_x = drawable_mod_undo->offset_x; offset_y = drawable_mod_undo->offset_y; drawable_mod_undo->buffer = g_object_ref (gimp_drawable_get_buffer (drawable)); gimp_item_get_offset (GIMP_ITEM (drawable), &drawable_mod_undo->offset_x, &drawable_mod_undo->offset_y); gimp_drawable_set_buffer_full (drawable, FALSE, NULL, buffer, offset_x, offset_y); g_object_unref (buffer); }
void gimp_channel_combine_ellipse_rect (GimpChannel *mask, GimpChannelOps op, gint x, gint y, gint w, gint h, gdouble rx, gdouble ry, gboolean antialias) { GimpChannelCombineData data; g_return_if_fail (GIMP_IS_CHANNEL (mask)); if (gimp_channel_combine_start (mask, op, GEGL_RECTANGLE (x, y, w, h), TRUE, FALSE, &data)) { GeglBuffer *buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); gimp_gegl_mask_combine_ellipse_rect (buffer, op, x, y, w, h, rx, ry, antialias); } gimp_channel_combine_end (mask, &data); }
GimpTempBuf * gimp_drawable_get_sub_preview (GimpDrawable *drawable, gint src_x, gint src_y, gint src_width, gint src_height, gint dest_width, gint dest_height) { GimpItem *item; GimpImage *image; GeglBuffer *buffer; GimpTempBuf *preview; gdouble scale; gint scaled_x; gint scaled_y; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (src_x >= 0, NULL); g_return_val_if_fail (src_y >= 0, NULL); g_return_val_if_fail (src_width > 0, NULL); g_return_val_if_fail (src_height > 0, NULL); g_return_val_if_fail (dest_width > 0, NULL); g_return_val_if_fail (dest_height > 0, NULL); item = GIMP_ITEM (drawable); g_return_val_if_fail ((src_x + src_width) <= gimp_item_get_width (item), NULL); g_return_val_if_fail ((src_y + src_height) <= gimp_item_get_height (item), NULL); image = gimp_item_get_image (item); if (! image->gimp->config->layer_previews) return NULL; buffer = gimp_drawable_get_buffer (drawable); preview = gimp_temp_buf_new (dest_width, dest_height, gimp_drawable_get_preview_format (drawable)); scale = MIN ((gdouble) dest_width / (gdouble) src_width, (gdouble) dest_height / (gdouble) src_height); scaled_x = RINT ((gdouble) src_x * scale); scaled_y = RINT ((gdouble) src_y * scale); gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, dest_width, dest_height), scale, gimp_temp_buf_get_format (preview), gimp_temp_buf_get_data (preview), GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); return preview; }
void gimp_channel_combine_rect (GimpChannel *mask, GimpChannelOps op, gint x, gint y, gint w, gint h) { GeglBuffer *buffer; g_return_if_fail (GIMP_IS_CHANNEL (mask)); buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); if (! gimp_gegl_mask_combine_rect (buffer, op, x, y, w, h)) return; gimp_rectangle_intersect (x, y, w, h, 0, 0, gimp_item_get_width (GIMP_ITEM (mask)), gimp_item_get_height (GIMP_ITEM (mask)), &x, &y, &w, &h); /* Determine new boundary */ if (mask->bounds_known && (op == GIMP_CHANNEL_OP_ADD) && ! mask->empty) { if (x < mask->x1) mask->x1 = x; if (y < mask->y1) mask->y1 = y; if ((x + w) > mask->x2) mask->x2 = (x + w); if ((y + h) > mask->y2) mask->y2 = (y + h); } else if (op == GIMP_CHANNEL_OP_REPLACE || mask->empty) { mask->empty = FALSE; mask->x1 = x; mask->y1 = y; mask->x2 = x + w; mask->y2 = y + h; } else { mask->bounds_known = FALSE; } mask->x1 = CLAMP (mask->x1, 0, gimp_item_get_width (GIMP_ITEM (mask))); mask->y1 = CLAMP (mask->y1, 0, gimp_item_get_height (GIMP_ITEM (mask))); mask->x2 = CLAMP (mask->x2, 0, gimp_item_get_width (GIMP_ITEM (mask))); mask->y2 = CLAMP (mask->y2, 0, gimp_item_get_height (GIMP_ITEM (mask))); gimp_drawable_update (GIMP_DRAWABLE (mask), x, y, w, h); }
static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[2]; GimpPDBStatusType status = GIMP_PDB_SUCCESS; GError *error = NULL; INIT_I18N (); gegl_init (NULL, NULL); *nreturn_vals = 1; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; gimp_get_data (SAVE_PROC, >mvals); if (save_dialog (param[1].data.d_int32)) { GeglBuffer *buffer; buffer = gimp_drawable_get_buffer (param[2].data.d_int32); if (save_image (param[3].data.d_string, buffer, &error)) { gimp_set_data (SAVE_PROC, >mvals, sizeof (GTMValues)); } else { status = GIMP_PDB_EXECUTION_ERROR; } g_object_unref (buffer); } else { status = GIMP_PDB_CANCEL; } if (status != GIMP_PDB_SUCCESS && error) { *nreturn_vals = 2; values[1].type = GIMP_PDB_STRING; values[1].data.d_string = error->message; } values[0].data.d_status = status; }
void gimp_drawable_foreground_extract_siox (GimpDrawable *mask, SioxState *state, SioxRefinementType refinement, gint smoothness, const gdouble sensitivity[3], gboolean multiblob, GimpProgress *progress) { GeglBuffer *buffer; gint x1, y1; gint x2, y2; g_return_if_fail (GIMP_IS_DRAWABLE (mask)); g_return_if_fail (babl_format_get_bytes_per_pixel (gimp_drawable_get_format (mask)) == 1); g_return_if_fail (state != NULL); g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); if (progress) gimp_progress_start (progress, _("Foreground Extraction"), FALSE); if (GIMP_IS_CHANNEL (mask)) { gimp_channel_bounds (GIMP_CHANNEL (mask), &x1, &y1, &x2, &y2); } else { x1 = 0; y1 = 0; x2 = gimp_item_get_width (GIMP_ITEM (mask)); y2 = gimp_item_get_height (GIMP_ITEM (mask)); } buffer = gimp_drawable_get_buffer (mask); siox_foreground_extract (state, refinement, gimp_gegl_buffer_get_tiles (buffer), x1, y1, x2, y2, smoothness, sensitivity, multiblob, (SioxProgressFunc) gimp_progress_set_value, progress); if (progress) gimp_progress_end (progress); gimp_drawable_update (mask, x1, y1, x2, y2); }
static void gimp_n_point_deformation_tool_apply_deformation (GimpNPointDeformationTool *npd_tool) { GimpTool *tool = GIMP_TOOL (npd_tool); GimpNPointDeformationOptions *npd_options; GeglBuffer *buffer; GimpImage *image; gint width, height, prev; npd_options = GIMP_N_POINT_DEFORMATION_TOOL_GET_OPTIONS (npd_tool); image = gimp_display_get_image (tool->display); buffer = gimp_drawable_get_buffer (tool->drawable); width = gegl_buffer_get_width (buffer); height = gegl_buffer_get_height (buffer); prev = npd_options->rigidity; npd_options->rigidity = 0; gimp_n_point_deformation_tool_set_options (npd_tool, npd_options); npd_options->rigidity = prev; gimp_drawable_push_undo (tool->drawable, _("N-Point Deformation"), NULL, 0, 0, width, height); gimp_gegl_apply_operation (NULL, NULL, _("N-Point Deformation"), npd_tool->npd_node, gimp_drawable_get_buffer (tool->drawable), NULL); gimp_drawable_update (tool->drawable, 0, 0, width, height); gimp_projection_flush (gimp_image_get_projection (image)); }
void gimp_channel_combine_mask (GimpChannel *mask, GimpChannel *add_on, GimpChannelOps op, gint off_x, gint off_y) { GeglBuffer *add_on_buffer; g_return_if_fail (GIMP_IS_CHANNEL (mask)); g_return_if_fail (GIMP_IS_CHANNEL (add_on)); add_on_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (add_on)); gimp_channel_combine_buffer (mask, add_on_buffer, op, off_x, off_y); }
static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[1]; GimpPDBStatusType status = GIMP_PDB_SUCCESS; gint32 drawable_id; gint x, y, width, height; *nreturn_vals = 1; *return_vals = values; gegl_init (NULL, NULL); values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; INIT_I18N(); drawable_id = param[2].data.d_drawable; if (gimp_drawable_mask_intersect (drawable_id, &x, &y, &width, &height)) { GeglBuffer *buffer; GeglBuffer *shadow_buffer; buffer = gimp_drawable_get_buffer (drawable_id); shadow_buffer = gimp_drawable_get_shadow_buffer (drawable_id); gegl_render_op (buffer, shadow_buffer, "gegl:invert", NULL); g_object_unref (shadow_buffer); /* flushes the shadow tiles */ g_object_unref (buffer); gimp_drawable_merge_shadow (drawable_id, TRUE); gimp_drawable_update (drawable_id, x, y, width, height); gimp_displays_flush (); } values[0].data.d_status = status; gegl_exit (); }
void gimp_paint_core_cancel (GimpPaintCore *core, GimpDrawable *drawable) { gint x, y; gint width, height; g_return_if_fail (GIMP_IS_PAINT_CORE (core)); g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); /* Determine if any part of the image has been altered-- * if nothing has, then just return... */ if ((core->x2 == core->x1) || (core->y2 == core->y1)) return; if (gimp_rectangle_intersect (core->x1, core->y1, core->x2 - core->x1, core->y2 - core->y1, 0, 0, gimp_item_get_width (GIMP_ITEM (drawable)), gimp_item_get_height (GIMP_ITEM (drawable)), &x, &y, &width, &height)) { gegl_buffer_copy (core->undo_buffer, GEGL_RECTANGLE (x, y, width, height), gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE (x, y, width, height)); } g_object_unref (core->undo_buffer); core->undo_buffer = NULL; if (core->saved_proj_buffer) { g_object_unref (core->saved_proj_buffer); core->saved_proj_buffer = NULL; } gimp_drawable_update (drawable, x, y, width, height); gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable)); }
SioxState * gimp_drawable_foreground_extract_siox_init (GimpDrawable *drawable, gint x, gint y, gint width, gint height) { GeglBuffer *buffer; const guchar *colormap = NULL; gboolean intersect; gint offset_x; gint offset_y; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); if (gimp_drawable_is_indexed (drawable)) colormap = gimp_drawable_get_colormap (drawable); gimp_item_get_offset (GIMP_ITEM (drawable), &offset_x, &offset_y); intersect = gimp_rectangle_intersect (offset_x, offset_y, gimp_item_get_width (GIMP_ITEM (drawable)), gimp_item_get_height (GIMP_ITEM (drawable)), x, y, width, height, &x, &y, &width, &height); /* FIXME: * Clear the mask outside the rectangle that we are working on? */ if (! intersect) return NULL; buffer = gimp_drawable_get_buffer (drawable); return siox_init (gimp_gegl_buffer_get_tiles (buffer), colormap, offset_x, offset_y, x, y, width, height); }
GimpLayerMask * gimp_layer_mask_new_from_buffer (GeglBuffer *buffer, GimpImage *image, const gchar *name, const GimpRGB *color) { GimpLayerMask *layer_mask; GeglBuffer *dest; g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL); g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); layer_mask = gimp_layer_mask_new (image, gegl_buffer_get_width (buffer), gegl_buffer_get_height (buffer), name, color); dest = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer_mask)); gegl_buffer_copy (buffer, NULL, dest, NULL); return layer_mask; }
void gimp_channel_select_channel (GimpChannel *channel, const gchar *undo_desc, GimpChannel *add_on, gint offset_x, gint offset_y, GimpChannelOps op, gboolean feather, gdouble feather_radius_x, gdouble feather_radius_y) { g_return_if_fail (GIMP_IS_CHANNEL (channel)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (channel))); g_return_if_fail (undo_desc != NULL); g_return_if_fail (GIMP_IS_CHANNEL (add_on)); gimp_channel_select_buffer (channel, undo_desc, gimp_drawable_get_buffer (GIMP_DRAWABLE (add_on)), offset_x, offset_y, op, feather, feather_radius_x, feather_radius_y); }
void gimp_channel_select_by_index (GimpChannel *channel, GimpDrawable *drawable, gint index, GimpChannelOps op, gboolean feather, gdouble feather_radius_x, gdouble feather_radius_y) { GeglBuffer *add_on; gint add_on_x = 0; gint add_on_y = 0; g_return_if_fail (GIMP_IS_CHANNEL (channel)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (channel))); g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_drawable_is_indexed (drawable)); add_on = gegl_buffer_new (GEGL_RECTANGLE (0, 0, gimp_item_get_width (GIMP_ITEM (drawable)), gimp_item_get_height (GIMP_ITEM (drawable))), babl_format ("Y float")); gimp_gegl_index_to_mask (gimp_drawable_get_buffer (drawable), NULL, gimp_drawable_get_format_without_alpha (drawable), add_on, NULL, index); gimp_item_get_offset (GIMP_ITEM (drawable), &add_on_x, &add_on_y); gimp_channel_select_buffer (channel, C_("undo-type", "Select by Indexed Color"), add_on, add_on_x, add_on_y, op, feather, feather_radius_x, feather_radius_y); g_object_unref (add_on); }
static void gimp_channel_combine_end (GimpChannel *mask, GimpChannelCombineData *data) { GeglBuffer *buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); gegl_buffer_set_abyss (buffer, gegl_buffer_get_extent (buffer)); gegl_buffer_thaw_changed (buffer); mask->bounds_known = data->bounds_known; if (data->bounds_known) { mask->empty = data->empty; if (data->empty) { mask->x1 = 0; mask->y1 = 0; mask->x2 = gimp_item_get_width (GIMP_ITEM (mask)); mask->y2 = gimp_item_get_height (GIMP_ITEM (mask)); } else { mask->x1 = data->bounds.x; mask->y1 = data->bounds.y; mask->x2 = data->bounds.x + data->bounds.width; mask->y2 = data->bounds.y + data->bounds.height; } } gimp_drawable_update (GIMP_DRAWABLE (mask), data->rect.x, data->rect.y, data->rect.width, data->rect.height); }
static void gimp_image_convert_profile_rgb (GimpImage *image, GimpColorProfile *src_profile, GimpColorProfile *dest_profile, GimpColorRenderingIntent intent, gboolean bpc, GimpProgress *progress) { GList *layers; GList *list; gint n_drawables; gint nth_drawable; layers = gimp_image_get_layer_list (image); n_drawables = g_list_length (layers); for (list = layers, nth_drawable = 0; list; list = g_list_next (list), nth_drawable++) { GimpDrawable *drawable = list->data; cmsHPROFILE src_lcms; cmsHPROFILE dest_lcms; const Babl *iter_format; cmsUInt32Number lcms_format; cmsUInt32Number flags; cmsHTRANSFORM transform; if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable))) continue; src_lcms = gimp_color_profile_get_lcms_profile (src_profile); dest_lcms = gimp_color_profile_get_lcms_profile (dest_profile); iter_format = gimp_color_profile_get_format (gimp_drawable_get_format (drawable), &lcms_format); flags = cmsFLAGS_NOOPTIMIZE; if (bpc) flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; transform = cmsCreateTransform (src_lcms, lcms_format, dest_lcms, lcms_format, intent, flags); if (transform) { GeglBuffer *buffer; GeglBufferIterator *iter; buffer = gimp_drawable_get_buffer (drawable); gimp_drawable_push_undo (drawable, NULL, NULL, 0, 0, gegl_buffer_get_width (buffer), gegl_buffer_get_height (buffer)); iter = gegl_buffer_iterator_new (buffer, NULL, 0, iter_format, GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { cmsDoTransform (transform, iter->data[0], iter->data[0], iter->length); } gimp_drawable_update (drawable, 0, 0, gegl_buffer_get_width (buffer), gegl_buffer_get_height (buffer)); cmsDeleteTransform (transform); } if (progress) gimp_progress_set_value (progress, (gdouble) nth_drawable / (gdouble) n_drawables); } g_list_free (layers); }
static GeglBuffer * gradient_precalc_shapeburst (GimpImage *image, GimpDrawable *drawable, const GeglRectangle *region, gdouble dist, GimpProgress *progress) { GimpChannel *mask; GeglBuffer *dist_buffer; GeglBuffer *temp_buffer; GeglNode *shapeburst; gdouble max; gfloat max_iteration; gimp_progress_set_text (progress, _("Calculating distance map")); /* allocate the distance map */ dist_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, region->width, region->height), babl_format ("Y float")); /* allocate the selection mask copy * XXX: its format should be the same of gimp:shapeburst input buffer * porting the op to 'float' should be reflected here as well */ temp_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, region->width, region->height), babl_format ("Y u8")); mask = gimp_image_get_mask (image); /* If the image mask is not empty, use it as the shape burst source */ if (! gimp_channel_is_empty (mask)) { gint x, y, width, height; gint off_x, off_y; gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height); gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); /* copy the mask to the temp mask */ gegl_buffer_copy (gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)), GEGL_RECTANGLE (x + off_x, y + off_y, width, height), temp_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); } else { /* If the intended drawable has an alpha channel, use that */ if (gimp_drawable_has_alpha (drawable)) { const Babl *component_format; component_format = babl_format ("A u8"); /* extract the aplha into the temp mask */ gegl_buffer_set_format (temp_buffer, component_format); gegl_buffer_copy (gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE (region->x, region->y, region->width, region->height), temp_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); gegl_buffer_set_format (temp_buffer, NULL); } else { GeglColor *white = gegl_color_new ("white"); /* Otherwise, just fill the shapeburst to white */ gegl_buffer_set_color (temp_buffer, NULL, white); g_object_unref (white); } } shapeburst = gegl_node_new_child (NULL, "operation", "gimp:shapeburst", NULL); gimp_gegl_progress_connect (shapeburst, progress, NULL); gimp_gegl_apply_operation (temp_buffer, NULL, NULL, shapeburst, dist_buffer, NULL); gegl_node_get (shapeburst, "max-iterations", &max, NULL); g_object_unref (shapeburst); max_iteration = max; g_object_unref (temp_buffer); /* normalize the shapeburst with the max iteration */ if (max_iteration > 0) { GeglBufferIterator *iter; iter = gegl_buffer_iterator_new (dist_buffer, NULL, 0, NULL, GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gint count = iter->length; gfloat *data = iter->data[0]; while (count--) *data++ /= max_iteration; } } return dist_buffer; }
void gimp_paint_core_paste (GimpPaintCore *core, const GimpTempBuf *paint_mask, gint paint_mask_offset_x, gint paint_mask_offset_y, GimpDrawable *drawable, gdouble paint_opacity, gdouble image_opacity, GimpLayerModeEffects paint_mode, GimpPaintApplicationMode mode) { gint width = gegl_buffer_get_width (core->paint_buffer); gint height = gegl_buffer_get_height (core->paint_buffer); if (core->applicator) { /* If the mode is CONSTANT: * combine the canvas buf, the paint mask to the canvas buffer */ if (mode == GIMP_PAINT_CONSTANT) { /* Some tools (ink) paint the mask to paint_core->canvas_buffer * directly. Don't need to copy it in this case. */ if (paint_mask != NULL) { GeglBuffer *paint_mask_buffer = gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask); gimp_gegl_combine_mask_weird (paint_mask_buffer, GEGL_RECTANGLE (paint_mask_offset_x, paint_mask_offset_y, width, height), core->canvas_buffer, GEGL_RECTANGLE (core->paint_buffer_x, core->paint_buffer_y, width, height), paint_opacity, GIMP_IS_AIRBRUSH (core)); g_object_unref (paint_mask_buffer); } gimp_gegl_apply_mask (core->canvas_buffer, GEGL_RECTANGLE (core->paint_buffer_x, core->paint_buffer_y, width, height), core->paint_buffer, GEGL_RECTANGLE (0, 0, width, height), 1.0); gimp_applicator_set_src_buffer (core->applicator, core->undo_buffer); } /* Otherwise: * combine the canvas buf and the paint mask to the canvas buf */ else { GeglBuffer *paint_mask_buffer = gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask); gimp_gegl_apply_mask (paint_mask_buffer, GEGL_RECTANGLE (paint_mask_offset_x, paint_mask_offset_y, width, height), core->paint_buffer, GEGL_RECTANGLE (0, 0, width, height), paint_opacity); g_object_unref (paint_mask_buffer); gimp_applicator_set_src_buffer (core->applicator, gimp_drawable_get_buffer (drawable)); } gimp_applicator_set_apply_buffer (core->applicator, core->paint_buffer); gimp_applicator_set_apply_offset (core->applicator, core->paint_buffer_x, core->paint_buffer_y); gimp_applicator_set_mode (core->applicator, image_opacity, paint_mode); /* apply the paint area to the image */ gimp_applicator_blit (core->applicator, GEGL_RECTANGLE (core->paint_buffer_x, core->paint_buffer_y, width, height)); } else { GimpTempBuf *paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer); GeglBuffer *dest_buffer; GeglBuffer *src_buffer; if (! paint_buf) return; if (core->comp_buffer) dest_buffer = core->comp_buffer; else dest_buffer = gimp_drawable_get_buffer (drawable); if (mode == GIMP_PAINT_CONSTANT) { /* This step is skipped by the ink tool, which writes * directly to canvas_buffer */ if (paint_mask != NULL) { /* Mix paint mask and canvas_buffer */ combine_paint_mask_to_canvas_mask (paint_mask, paint_mask_offset_x, paint_mask_offset_y, core->canvas_buffer, core->paint_buffer_x, core->paint_buffer_y, paint_opacity, GIMP_IS_AIRBRUSH (core)); } /* Write canvas_buffer to paint_buf */ canvas_buffer_to_paint_buf_alpha (paint_buf, core->canvas_buffer, core->paint_buffer_x, core->paint_buffer_y); /* undo buf -> paint_buf -> dest_buffer */ src_buffer = core->undo_buffer; } else { g_return_if_fail (paint_mask); /* Write paint_mask to paint_buf, does not modify canvas_buffer */ paint_mask_to_paint_buffer (paint_mask, paint_mask_offset_x, paint_mask_offset_y, paint_buf, paint_opacity); /* dest_buffer -> paint_buf -> dest_buffer */ src_buffer = dest_buffer; } do_layer_blend (src_buffer, dest_buffer, paint_buf, core->mask_buffer, image_opacity, core->paint_buffer_x, core->paint_buffer_y, core->mask_x_offset, core->mask_y_offset, core->linear_mode, paint_mode); if (core->comp_buffer) { mask_components_onto (src_buffer, core->comp_buffer, gimp_drawable_get_buffer (drawable), GEGL_RECTANGLE(core->paint_buffer_x, core->paint_buffer_y, width, height), gimp_drawable_get_active_mask (drawable), core->linear_mode); } } /* Update the undo extents */ core->x1 = MIN (core->x1, core->paint_buffer_x); core->y1 = MIN (core->y1, core->paint_buffer_y); core->x2 = MAX (core->x2, core->paint_buffer_x + width); core->y2 = MAX (core->y2, core->paint_buffer_y + height); /* Update the drawable */ gimp_drawable_update (drawable, core->paint_buffer_x, core->paint_buffer_y, width, height); }
gboolean gimp_paint_core_start (GimpPaintCore *core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, GError **error) { GimpImage *image; GimpItem *item; GimpChannel *mask; g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE); g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE); g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE); g_return_val_if_fail (coords != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); item = GIMP_ITEM (drawable); image = gimp_item_get_image (item); if (core->stroke_buffer) { g_array_free (core->stroke_buffer, TRUE); core->stroke_buffer = NULL; } core->stroke_buffer = g_array_sized_new (TRUE, TRUE, sizeof (GimpCoords), STROKE_BUFFER_INIT_SIZE); /* remember the last stroke's endpoint for later undo */ core->start_coords = core->last_coords; core->cur_coords = *coords; if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawable, paint_options, coords, error)) { return FALSE; } /* Allocate the undo structure */ if (core->undo_buffer) g_object_unref (core->undo_buffer); core->undo_buffer = gegl_buffer_dup (gimp_drawable_get_buffer (drawable)); /* Allocate the saved proj structure */ if (core->saved_proj_buffer) { g_object_unref (core->saved_proj_buffer); core->saved_proj_buffer = NULL; } if (core->use_saved_proj) { GeglBuffer *buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image)); core->saved_proj_buffer = gegl_buffer_dup (buffer); } /* Allocate the canvas blocks structure */ if (core->canvas_buffer) g_object_unref (core->canvas_buffer); core->canvas_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, gimp_item_get_width (item), gimp_item_get_height (item)), babl_format ("Y float")); /* Get the initial undo extents */ core->x1 = core->x2 = core->cur_coords.x; core->y1 = core->y2 = core->cur_coords.y; core->last_paint.x = -1e6; core->last_paint.y = -1e6; mask = gimp_image_get_mask (image); /* don't apply the mask to itself and don't apply an empty mask */ if (GIMP_DRAWABLE (mask) != drawable && ! gimp_channel_is_empty (mask)) { GeglBuffer *mask_buffer; gint offset_x; gint offset_y; mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); gimp_item_get_offset (item, &offset_x, &offset_y); core->mask_buffer = g_object_ref (mask_buffer); core->mask_x_offset = -offset_x; core->mask_y_offset = -offset_y; } else { core->mask_buffer = NULL; } core->linear_mode = gimp_drawable_get_linear (drawable); if (paint_options->use_applicator) { core->applicator = gimp_applicator_new (NULL, core->linear_mode); if (core->mask_buffer) { gimp_applicator_set_mask_buffer (core->applicator, core->mask_buffer); gimp_applicator_set_mask_offset (core->applicator, core->mask_x_offset, core->mask_y_offset); } gimp_applicator_set_affect (core->applicator, gimp_drawable_get_active_mask (drawable)); gimp_applicator_set_dest_buffer (core->applicator, gimp_drawable_get_buffer (drawable)); } else { if (core->comp_buffer) { g_object_unref (core->comp_buffer); core->comp_buffer = NULL; } /* Allocate the scratch buffer if there's a component mask */ if (gimp_drawable_get_active_mask (drawable) != GIMP_COMPONENT_ALL) { const Babl *format; if (core->linear_mode) format = babl_format ("RGBA float"); else format = babl_format ("R'G'B'A float"); core->comp_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, gimp_item_get_width (item), gimp_item_get_height (item)), format); } } /* Freeze the drawable preview so that it isn't constantly updated. */ gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable)); return TRUE; }
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); }
static gboolean gimp_channel_combine_start (GimpChannel *mask, GimpChannelOps op, const GeglRectangle *rect, gboolean full_extent, gboolean full_value, GimpChannelCombineData *data) { GeglBuffer *buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); GeglRectangle extent; gboolean intersects; extent.x = 0; extent.y = 0; extent.width = gimp_item_get_width (GIMP_ITEM (mask)); extent.height = gimp_item_get_height (GIMP_ITEM (mask)); intersects = gegl_rectangle_intersect (&data->rect, rect, &extent); data->bounds_known = mask->bounds_known; data->empty = mask->empty; data->bounds.x = mask->x1; data->bounds.y = mask->y1; data->bounds.width = mask->x2 - mask->x1; data->bounds.height = mask->y2 - mask->y1; gegl_buffer_freeze_changed (buffer); /* Determine new boundary */ switch (op) { case GIMP_CHANNEL_OP_REPLACE: gimp_channel_combine_clear (mask, NULL); if (! intersects) { data->bounds_known = TRUE; data->empty = TRUE; return FALSE; } data->bounds_known = FALSE; if (full_extent) { data->bounds_known = TRUE; data->empty = FALSE; data->bounds = data->rect; } break; case GIMP_CHANNEL_OP_ADD: if (! intersects) return FALSE; data->bounds_known = FALSE; if (full_extent && (mask->bounds_known || gegl_rectangle_equal (&data->rect, &extent))) { data->bounds_known = TRUE; data->empty = FALSE; if (mask->bounds_known && ! mask->empty) { gegl_rectangle_bounding_box (&data->bounds, &data->bounds, &data->rect); } else { data->bounds = data->rect; } } break; case GIMP_CHANNEL_OP_SUBTRACT: if (intersects && mask->bounds_known) { if (mask->empty) { intersects = FALSE; } else { intersects = gegl_rectangle_intersect (&data->rect, &data->rect, &data->bounds); } } if (! intersects) return FALSE; if (full_value && gegl_rectangle_contains (&data->rect, mask->bounds_known ? &data->bounds : &extent)) { gimp_channel_combine_clear (mask, NULL); data->bounds_known = TRUE; data->empty = TRUE; return FALSE; } data->bounds_known = FALSE; gegl_buffer_set_abyss (buffer, &data->rect); break; case GIMP_CHANNEL_OP_INTERSECT: if (intersects && mask->bounds_known) { if (mask->empty) { intersects = FALSE; } else { intersects = gegl_rectangle_intersect (&data->rect, &data->rect, &data->bounds); } } if (! intersects) { gimp_channel_combine_clear (mask, NULL); data->bounds_known = TRUE; data->empty = TRUE; return FALSE; } if (full_value && mask->bounds_known && gegl_rectangle_contains (&data->rect, &data->bounds)) { return FALSE; } data->bounds_known = FALSE; gimp_channel_combine_clear_complement (mask, &data->rect); gegl_buffer_set_abyss (buffer, &data->rect); break; } return TRUE; }