static GimpChannel * gimp_by_color_select_tool_get_mask (GimpRegionSelectTool *region_select, GimpDisplay *display) { GimpTool *tool = GIMP_TOOL (region_select); GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool); GimpDrawable *drawable; GimpPickable *pickable; GimpRGB color; gint x, y; drawable = gimp_image_get_active_drawable (display->image); x = region_select->x; y = region_select->y; if (! options->sample_merged) { gint off_x, off_y; gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y); x -= off_x; y -= off_y; pickable = GIMP_PICKABLE (drawable); } else { pickable = GIMP_PICKABLE (display->image->projection); } gimp_pickable_flush (pickable); if (gimp_pickable_get_color_at (pickable, x, y, &color)) return gimp_image_contiguous_region_by_color (display->image, drawable, options->sample_merged, options->antialias, options->threshold, options->select_transparent, options->select_criterion, &color); else return NULL; }
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); }
void gimp_source_core_motion (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options); GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); GimpPickable *src_pickable = NULL; 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; gdouble opacity; opacity = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist); if (opacity == 0.0) return; src_offset_x = source_core->offset_x; src_offset_y = source_core->offset_y; if (options->use_source) { 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 (gimp_image_get_projection (src_image)); gimp_item_offsets (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_area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); if (! paint_area) return; paint_area_offset_x = 0; paint_area_offset_y = 0; paint_area_width = paint_area->width; paint_area_height = paint_area->height; if (options->use_source && ! GIMP_SOURCE_CORE_GET_CLASS (source_core)->get_source (source_core, drawable, paint_options, src_pickable, src_offset_x, src_offset_y, paint_area, &paint_area_offset_x, &paint_area_offset_y, &paint_area_width, &paint_area_height, &srcPR)) { return; } /* Set the paint area to transparent */ temp_buf_data_clear (paint_area); GIMP_SOURCE_CORE_GET_CLASS (source_core)->motion (source_core, drawable, paint_options, opacity, src_pickable, &srcPR, src_offset_x, src_offset_y, paint_area, paint_area_offset_x, paint_area_offset_y, paint_area_width, paint_area_height); }
GeglBuffer * gimp_image_contiguous_region_by_seed (GimpImage *image, GimpDrawable *drawable, gboolean sample_merged, gboolean antialias, gfloat threshold, gboolean select_transparent, GimpSelectCriterion select_criterion, gint x, gint y) { GimpPickable *pickable; GeglBuffer *src_buffer; GeglBuffer *mask_buffer; const Babl *format; gint n_components; gboolean has_alpha; gfloat start_col[MAX_CHANNELS]; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); if (sample_merged) pickable = GIMP_PICKABLE (image); else pickable = GIMP_PICKABLE (drawable); gimp_pickable_flush (pickable); src_buffer = gimp_pickable_get_buffer (pickable); format = choose_format (src_buffer, select_criterion, &n_components, &has_alpha); gegl_buffer_sample (src_buffer, x, y, NULL, start_col, format, GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); if (has_alpha) { if (select_transparent) { /* don't select transparent regions if the start pixel isn't * fully transparent */ if (start_col[n_components - 1] > 0) select_transparent = FALSE; } } else { select_transparent = FALSE; } mask_buffer = gegl_buffer_new (gegl_buffer_get_extent (src_buffer), babl_format ("Y float")); find_contiguous_region_helper (src_buffer, mask_buffer, format, n_components, has_alpha, select_transparent, select_criterion, antialias, threshold, x, y, start_col); return mask_buffer; }
GeglBuffer * gimp_image_contiguous_region_by_color (GimpImage *image, GimpDrawable *drawable, gboolean sample_merged, gboolean antialias, gfloat threshold, gboolean select_transparent, GimpSelectCriterion select_criterion, const GimpRGB *color) { /* Scan over the image's active layer, finding pixels within the * specified threshold from the given R, G, & B values. If * antialiasing is on, use the same antialiasing scheme as in * fuzzy_select. Modify the image's mask to reflect the * additional selection */ GeglBufferIterator *iter; GimpPickable *pickable; GeglBuffer *src_buffer; GeglBuffer *mask_buffer; const Babl *format; gint n_components; gboolean has_alpha; gfloat start_col[MAX_CHANNELS]; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (color != NULL, NULL); if (sample_merged) pickable = GIMP_PICKABLE (image); else pickable = GIMP_PICKABLE (drawable); gimp_pickable_flush (pickable); src_buffer = gimp_pickable_get_buffer (pickable); format = choose_format (src_buffer, select_criterion, &n_components, &has_alpha); gimp_rgba_get_pixel (color, format, start_col); if (has_alpha) { if (select_transparent) { /* don't select transparancy if "color" isn't fully transparent */ if (start_col[n_components - 1] > 0.0) select_transparent = FALSE; } } else { select_transparent = FALSE; } mask_buffer = gegl_buffer_new (gegl_buffer_get_extent (src_buffer), babl_format ("Y float")); iter = gegl_buffer_iterator_new (src_buffer, NULL, 0, format, GEGL_BUFFER_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, mask_buffer, NULL, 0, babl_format ("Y float"), GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { const gfloat *src = iter->data[0]; gfloat *dest = iter->data[1]; gint count = iter->length; while (count--) { /* Find how closely the colors match */ *dest = pixel_difference (start_col, src, antialias, threshold, n_components, has_alpha, select_transparent, select_criterion); src += n_components; dest += 1; } } return mask_buffer; }
gboolean gimp_image_crop_auto_shrink (GimpImage *image, gint x1, gint y1, gint x2, gint y2, gboolean active_drawable_only, gint *shrunk_x1, gint *shrunk_y1, gint *shrunk_x2, gint *shrunk_y2) { GimpDrawable *active_drawable = NULL; GimpPickable *pickable; ColorsEqualFunc colors_equal_func; guchar bgcolor[MAX_CHANNELS] = { 0, 0, 0, 0 }; gboolean has_alpha; PixelRegion PR; guchar *buffer = NULL; gint width, height; GimpImageType type; gint bytes; gint x, y, abort; gboolean retval = FALSE; g_return_val_if_fail (image != NULL, FALSE); g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); g_return_val_if_fail (shrunk_x1 != NULL, FALSE); g_return_val_if_fail (shrunk_y1 != NULL, FALSE); g_return_val_if_fail (shrunk_x2 != NULL, FALSE); g_return_val_if_fail (shrunk_y2 != NULL, FALSE); gimp_set_busy (image->gimp); /* You should always keep in mind that crop->tx2 and crop->ty2 are the NOT the coordinates of the bottomright corner of the area to be cropped. They point at the pixel located one to the right and one to the bottom. */ if (active_drawable_only) { active_drawable = gimp_image_get_active_drawable (image); if (! active_drawable) goto FINISH; pickable = GIMP_PICKABLE (active_drawable); } else { pickable = GIMP_PICKABLE (image->projection); } gimp_pickable_flush (pickable); type = gimp_pickable_get_image_type (pickable); bytes = GIMP_IMAGE_TYPE_BYTES (type); has_alpha = GIMP_IMAGE_TYPE_HAS_ALPHA (type); switch (gimp_image_crop_guess_bgcolor (pickable, bytes, has_alpha, bgcolor, x1, x2-1, y1, y2-1)) { case AUTO_CROP_ALPHA: colors_equal_func = (ColorsEqualFunc) gimp_image_crop_colors_alpha; break; case AUTO_CROP_COLOR: colors_equal_func = (ColorsEqualFunc) gimp_image_crop_colors_equal; break; default: goto FINISH; break; } width = x2 - x1; height = y2 - y1; pixel_region_init (&PR, gimp_pickable_get_tiles (pickable), x1, y1, width, height, FALSE); /* The following could be optimized further by processing * the smaller side first instead of defaulting to width --Sven */ buffer = g_malloc ((width > height ? width : height) * bytes); /* Check how many of the top lines are uniform/transparent. */ abort = FALSE; for (y = y1; y < y2 && !abort; y++) { pixel_region_get_row (&PR, x1, y, width, buffer, 1); for (x = 0; x < width && !abort; x++) abort = !(colors_equal_func) (bgcolor, buffer + x * bytes, bytes); } if (y == y2 && !abort) goto FINISH; y1 = y - 1; /* Check how many of the bottom lines are uniform/transparent. */ abort = FALSE; for (y = y2; y > y1 && !abort; y--) { pixel_region_get_row (&PR, x1, y-1 , width, buffer, 1); for (x = 0; x < width && !abort; x++) abort = !(colors_equal_func) (bgcolor, buffer + x * bytes, bytes); } y2 = y + 1; /* compute a new height for the next operations */ height = y2 - y1; /* Check how many of the left lines are uniform/transparent. */ abort = FALSE; for (x = x1; x < x2 && !abort; x++) { pixel_region_get_col (&PR, x, y1, height, buffer, 1); for (y = 0; y < height && !abort; y++) abort = !(colors_equal_func) (bgcolor, buffer + y * bytes, bytes); } x1 = x - 1; /* Check how many of the right lines are uniform/transparent. */ abort = FALSE; for (x = x2; x > x1 && !abort; x--) { pixel_region_get_col (&PR, x-1, y1, height, buffer, 1); for (y = 0; y < height && !abort; y++) abort = !(colors_equal_func) (bgcolor, buffer + y * bytes, bytes); } x2 = x + 1; *shrunk_x1 = x1; *shrunk_y1 = y1; *shrunk_x2 = x2; *shrunk_y2 = y2; retval = TRUE; FINISH: g_free (buffer); gimp_unset_busy (image->gimp); return retval; }
GeglBuffer * gimp_pickable_contiguous_region_by_seed (GimpPickable *pickable, gboolean antialias, gfloat threshold, gboolean select_transparent, GimpSelectCriterion select_criterion, gboolean diagonal_neighbors, gint x, gint y) { GeglBuffer *src_buffer; GeglBuffer *mask_buffer; const Babl *format; GeglRectangle extent; gint n_components; gboolean has_alpha; gfloat start_col[MAX_CHANNELS]; g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL); gimp_pickable_flush (pickable); src_buffer = gimp_pickable_get_buffer (pickable); format = choose_format (src_buffer, select_criterion, &n_components, &has_alpha); gegl_buffer_sample (src_buffer, x, y, NULL, start_col, format, GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); if (has_alpha) { if (select_transparent) { /* don't select transparent regions if the start pixel isn't * fully transparent */ if (start_col[n_components - 1] > 0) select_transparent = FALSE; } } else { select_transparent = FALSE; } extent = *gegl_buffer_get_extent (src_buffer); mask_buffer = gegl_buffer_new (&extent, babl_format ("Y float")); if (x >= extent.x && x < (extent.x + extent.width) && y >= extent.y && y < (extent.y + extent.height)) { GIMP_TIMER_START(); find_contiguous_region (src_buffer, mask_buffer, format, n_components, has_alpha, select_transparent, select_criterion, antialias, threshold, diagonal_neighbors, x, y, start_col); GIMP_TIMER_END("foo"); } return mask_buffer; }