static GdkSegment * gimp_region_select_tool_calculate (GimpRegionSelectTool *region_sel, GimpDisplay *display, gint *num_segs) { GimpTool *tool = GIMP_TOOL (region_sel); GimpRegionSelectOptions *options = GIMP_REGION_SELECT_TOOL_GET_OPTIONS (tool); GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (display->shell); GimpDrawable *drawable; GdkSegment *segs; BoundSeg *bsegs; PixelRegion maskPR; drawable = gimp_image_get_active_drawable (display->image); gimp_display_shell_set_override_cursor (shell, GDK_WATCH); if (region_sel->region_mask) g_object_unref (region_sel->region_mask); region_sel->region_mask = GIMP_REGION_SELECT_TOOL_GET_CLASS (region_sel)->get_mask (region_sel, display); if (! region_sel->region_mask) { gimp_display_shell_unset_override_cursor (shell); *num_segs = 0; return NULL; } /* calculate and allocate a new segment array which represents the * boundary of the contiguous region */ pixel_region_init (&maskPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (region_sel->region_mask)), 0, 0, gimp_item_width (GIMP_ITEM (region_sel->region_mask)), gimp_item_height (GIMP_ITEM (region_sel->region_mask)), FALSE); bsegs = boundary_find (&maskPR, BOUNDARY_WITHIN_BOUNDS, 0, 0, gimp_item_width (GIMP_ITEM (region_sel->region_mask)), gimp_item_height (GIMP_ITEM (region_sel->region_mask)), BOUNDARY_HALF_WAY, num_segs); segs = g_new (GdkSegment, *num_segs); gimp_display_shell_transform_segments (shell, bsegs, segs, *num_segs, ! options->sample_merged); g_free (bsegs); gimp_display_shell_unset_override_cursor (shell); return segs; }
void gimp_layer_mask_set_show (GimpLayerMask *layer_mask, gboolean show, gboolean push_undo) { g_return_if_fail (GIMP_IS_LAYER_MASK (layer_mask)); if (layer_mask->show_mask != show) { GimpImage *image = GIMP_ITEM (layer_mask)->image; if (push_undo) gimp_image_undo_push_layer_mask_show (image, _("Show Layer Mask"), layer_mask); layer_mask->show_mask = show ? TRUE : FALSE; if (layer_mask->layer) { GimpDrawable *drawable = GIMP_DRAWABLE (layer_mask->layer); gimp_drawable_update (drawable, 0, 0, gimp_item_width (GIMP_ITEM (drawable)), gimp_item_height (GIMP_ITEM (drawable))); } g_signal_emit (layer_mask, layer_mask_signals[SHOW_CHANGED], 0); } }
static void gimp_image_map_tool_map (GimpImageMapTool *tool) { GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (GIMP_TOOL (tool)->display->shell); GimpItem *item = GIMP_ITEM (tool->drawable); gint x, y; gint w, h; gint off_x, off_y; GeglRectangle visible; GIMP_IMAGE_MAP_TOOL_GET_CLASS (tool)->map (tool); gimp_display_shell_untransform_viewport (shell, &x, &y, &w, &h); gimp_item_offsets (item, &off_x, &off_y); gimp_rectangle_intersect (x, y, w, h, off_x, off_y, gimp_item_width (item), gimp_item_height (item), &visible.x, &visible.y, &visible.width, &visible.height); visible.x -= off_x; visible.y -= off_y; gimp_image_map_apply (tool->image_map, &visible); }
gboolean gimp_item_is_in_set (GimpItem *item, GimpItemSet set) { g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE); switch (set) { case GIMP_ITEM_SET_NONE: return FALSE; case GIMP_ITEM_SET_ALL: return TRUE; case GIMP_ITEM_SET_IMAGE_SIZED: return (gimp_item_width (item) == gimp_image_get_width (item->image) && gimp_item_height (item) == gimp_image_get_height (item->image)); case GIMP_ITEM_SET_VISIBLE: return gimp_item_get_visible (item); case GIMP_ITEM_SET_LINKED: return gimp_item_get_linked (item); } return FALSE; }
static GimpLayer * select_layer_by_coords (GimpImage *image, gint x, gint y) { GList *list; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); for (list = GIMP_LIST (image->layers)->list; list; list = g_list_next (list)) { GimpLayer *layer = list->data; gint off_x, off_y; gint width, height; if (! gimp_item_get_visible (GIMP_ITEM (layer))) continue; gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); width = gimp_item_width (GIMP_ITEM (layer)); height = gimp_item_height (GIMP_ITEM (layer)); if (off_x <= x && off_y <= y && x < off_x + width && y < off_y + height) { return layer; } } return NULL; }
static TempBuf * gimp_drawable_preview_private (GimpDrawable *drawable, gint width, gint height) { TempBuf *ret_buf; if (! drawable->preview_valid || ! (ret_buf = gimp_preview_cache_get (&drawable->preview_cache, width, height))) { GimpItem *item = GIMP_ITEM (drawable); ret_buf = gimp_drawable_get_sub_preview (drawable, 0, 0, gimp_item_width (item), gimp_item_height (item), width, height); if (! drawable->preview_valid) gimp_preview_cache_invalidate (&drawable->preview_cache); drawable->preview_valid = TRUE; gimp_preview_cache_add (&drawable->preview_cache, ret_buf); } return ret_buf; }
/** * gimp_item_scale_by_factors: * @item: Item to be transformed by explicit width and height factors. * @w_factor: scale factor to apply to width and horizontal offset * @h_factor: scale factor to apply to height and vertical offset * @interpolation: * @progress: * * Scales item dimensions and offsets by uniform width and * height factors. * * Use gimp_item_scale_by_factors() in circumstances when the same * width and height scaling factors are to be uniformly applied to a * set of items. In this context, the item's dimensions and offsets * from the sides of the containing image all change by these * predetermined factors. By fiat, the fixed point of the transform is * the upper left hand corner of the image. Returns #FALSE if a * requested scale factor is zero or if a scaling zero's out a item * dimension; returns #TRUE otherwise. * * Use gimp_item_scale() in circumstances where new item width * and height dimensions are predetermined instead. * * Side effects: Undo set created for item. Old item imagery * scaled & painted to new item tiles. * * Returns: #TRUE, if the scaled item has positive dimensions * #FALSE if the scaled item has at least one zero dimension **/ gboolean gimp_item_scale_by_factors (GimpItem *item, gdouble w_factor, gdouble h_factor, GimpInterpolationType interpolation, GimpProgress *progress) { gint new_width, new_height; gint new_offset_x, new_offset_y; g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE); g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE); if (w_factor == 0.0 || h_factor == 0.0) { g_warning ("%s: requested width or height scale equals zero", G_STRFUNC); return FALSE; } new_offset_x = ROUND (w_factor * (gdouble) item->offset_x); new_offset_y = ROUND (h_factor * (gdouble) item->offset_y); new_width = ROUND (w_factor * (gdouble) gimp_item_width (item)); new_height = ROUND (h_factor * (gdouble) gimp_item_height (item)); if (new_width != 0 && new_height != 0) { gimp_item_scale (item, new_width, new_height, new_offset_x, new_offset_y, interpolation, progress); return TRUE; } return FALSE; }
void gimp_layer_mask_set_apply (GimpLayerMask *layer_mask, gboolean apply, gboolean push_undo) { g_return_if_fail (GIMP_IS_LAYER_MASK (layer_mask)); if (layer_mask->apply_mask != apply) { GimpImage *image = GIMP_ITEM (layer_mask)->image; if (push_undo) gimp_image_undo_push_layer_mask_apply (image, _("Apply Layer Mask"), layer_mask); layer_mask->apply_mask = apply ? TRUE : FALSE; if (layer_mask->layer) { GimpDrawable *drawable = GIMP_DRAWABLE (layer_mask->layer); gimp_drawable_update (drawable, 0, 0, gimp_item_width (GIMP_ITEM (drawable)), gimp_item_height (GIMP_ITEM (drawable))); } g_signal_emit (layer_mask, layer_mask_signals[APPLY_CHANGED], 0); } }
gboolean gimp_item_get_popup_size (GimpViewable *viewable, gint width, gint height, gboolean dot_for_dot, gint *popup_width, gint *popup_height) { GimpItem *item = GIMP_ITEM (viewable); GimpImage *image = gimp_item_get_image (item); if (image && ! image->gimp->config->layer_previews) return FALSE; if (gimp_item_width (item) > width || gimp_item_height (item) > height) { gboolean scaling_up; gdouble xres = 1.0; gdouble yres = 1.0; if (image) gimp_image_get_resolution (image, &xres, &yres); gimp_viewable_calc_preview_size (gimp_item_width (item), gimp_item_height (item), width * 2, height * 2, dot_for_dot, xres, yres, popup_width, popup_height, &scaling_up); if (scaling_up) { *popup_width = gimp_item_width (item); *popup_width = gimp_item_height (item); } return TRUE; } return FALSE; }
static GimpItem * gimp_item_real_duplicate (GimpItem *item, GType new_type) { GimpItem *new_item; gchar *new_name; g_return_val_if_fail (GIMP_IS_ITEM (item), NULL); g_return_val_if_fail (GIMP_IS_IMAGE (item->image), NULL); g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_ITEM), NULL); /* formulate the new name */ { const gchar *name; gchar *ext; gint number; gint len; name = gimp_object_get_name (GIMP_OBJECT (item)); g_return_val_if_fail (name != NULL, NULL); ext = strrchr (name, '#'); len = strlen (_("copy")); if ((strlen (name) >= len && strcmp (&name[strlen (name) - len], _("copy")) == 0) || (ext && (number = atoi (ext + 1)) > 0 && ((int)(log10 (number) + 1)) == strlen (ext + 1))) { /* don't have redundant "copy"s */ new_name = g_strdup (name); } else { new_name = g_strdup_printf (_("%s copy"), name); } } new_item = g_object_new (new_type, NULL); gimp_item_configure (new_item, gimp_item_get_image (item), item->offset_x, item->offset_y, gimp_item_width (item), gimp_item_height (item), new_name); g_free (new_name); g_object_unref (new_item->parasites); new_item->parasites = gimp_parasite_list_copy (item->parasites); new_item->visible = gimp_item_get_visible (item); new_item->linked = gimp_item_get_linked (item); return new_item; }
void gimp_channel_select_round_rect (GimpChannel *channel, gint x, gint y, gint w, gint h, gdouble corner_radius_x, gdouble corner_radius_y, GimpChannelOps op, gboolean antialias, gboolean feather, gdouble feather_radius_x, gdouble feather_radius_y, gboolean push_undo) { g_return_if_fail (GIMP_IS_CHANNEL (channel)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (channel))); if (push_undo) gimp_channel_push_undo (channel, Q_("command|Rounded Rectangle Select")); /* if applicable, replace the current selection */ if (op == GIMP_CHANNEL_OP_REPLACE) gimp_channel_clear (channel, NULL, FALSE); /* if feathering for rect, make a new mask with the * rectangle and feather that with the old mask */ if (feather || op == GIMP_CHANNEL_OP_INTERSECT) { GimpItem *item = GIMP_ITEM (channel); GimpChannel *add_on; add_on = gimp_channel_new_mask (gimp_item_get_image (item), gimp_item_width (item), gimp_item_height (item)); gimp_channel_combine_ellipse_rect (add_on, GIMP_CHANNEL_OP_ADD, x, y, w, h, corner_radius_x, corner_radius_y, antialias); if (feather) gimp_channel_feather (add_on, feather_radius_x, feather_radius_y, FALSE /* no undo */); gimp_channel_combine_mask (channel, add_on, op, 0, 0); g_object_unref (add_on); } else { gimp_channel_combine_ellipse_rect (channel, op, x, y, w, h, corner_radius_x, corner_radius_y, antialias); } }
/** * gimp_item_scale_by_origin: * @item: The item to be transformed by width & height scale factors * @new_width: The width that item will acquire * @new_height: The height that the item will acquire * @interpolation: * @progress: * @local_origin: sets fixed point of the scaling transform. See below. * * Sets item dimensions to new_width and * new_height. Derives vertical and horizontal scaling * transforms from new width and height. If local_origin is * #TRUE, the fixed point of the scaling transform coincides * with the item's center point. Otherwise, the fixed * point is taken to be [-item->offset_x, -item->offset_y]. * * Since this function derives scale factors from new and * current item dimensions, these factors will vary from * item to item because of aliasing artifacts; factor * variations among items can be quite large where item * dimensions approach pixel dimensions. Use * gimp_item_scale_by_factors() where constant scales are to * be uniformly applied to a number of items. * * Side effects: undo set created for item. * Old item imagery scaled * & painted to new item tiles **/ void gimp_item_scale_by_origin (GimpItem *item, gint new_width, gint new_height, GimpInterpolationType interpolation, GimpProgress *progress, gboolean local_origin) { gint new_offset_x, new_offset_y; g_return_if_fail (GIMP_IS_ITEM (item)); g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress)); if (new_width == 0 || new_height == 0) { g_warning ("%s: requested width or height equals zero", G_STRFUNC); return; } if (local_origin) { new_offset_x = (item->offset_x + ((gimp_item_width (item) - new_width) / 2.0)); new_offset_y = (item->offset_y + ((gimp_item_height (item) - new_height) / 2.0)); } else { new_offset_x = (gint) (((gdouble) new_width * (gdouble) item->offset_x / (gdouble) gimp_item_width (item))); new_offset_y = (gint) (((gdouble) new_height * (gdouble) item->offset_y / (gdouble) gimp_item_height (item))); } gimp_item_scale (item, new_width, new_height, new_offset_x, new_offset_y, interpolation, progress); }
void gimp_image_resize_to_layers (GimpImage *image, GimpContext *context, GimpProgress *progress) { GList *list = GIMP_LIST (image->layers)->list; GimpItem *item; gint min_x, max_x; gint min_y, max_y; if (!list) return; /* figure out starting values */ item = list->data; min_x = item->offset_x; min_y = item->offset_y; max_x = item->offset_x + gimp_item_width (item); max_y = item->offset_y + gimp_item_height (item); /* Respect all layers */ for (list = g_list_next (list); list; list = g_list_next (list)) { item = list->data; min_x = MIN (min_x, item->offset_x); min_y = MIN (min_y, item->offset_y); max_x = MAX (max_x, item->offset_x + gimp_item_width (item)); max_y = MAX (max_y, item->offset_y + gimp_item_height (item)); } gimp_image_resize (image, context, max_x - min_x, max_y - min_y, - min_x, - min_y, progress); }
void floating_sel_restore (GimpLayer *layer, gint x, gint y, gint w, gint h) { PixelRegion srcPR, destPR; gint offx, offy; gint x1, y1, x2, y2; g_return_if_fail (GIMP_IS_LAYER (layer)); g_return_if_fail (gimp_layer_is_floating_sel (layer)); /* What this function does is "uncover" the specified area in the * drawable that this floating selection obscures. We do this so * that either the floating selection can be removed or it can be * translated */ /* Find the minimum area we need to uncover -- in image space */ gimp_item_offsets (GIMP_ITEM (layer->fs.drawable), &offx, &offy); x1 = MAX (GIMP_ITEM (layer)->offset_x, offx); y1 = MAX (GIMP_ITEM (layer)->offset_y, offy); x2 = MIN (GIMP_ITEM (layer)->offset_x + GIMP_ITEM (layer)->width, offx + gimp_item_width (GIMP_ITEM (layer->fs.drawable))); y2 = MIN (GIMP_ITEM(layer)->offset_y + GIMP_ITEM (layer)->height, offy + gimp_item_height (GIMP_ITEM (layer->fs.drawable))); x1 = CLAMP (x, x1, x2); y1 = CLAMP (y, y1, y2); x2 = CLAMP (x + w, x1, x2); y2 = CLAMP (y + h, y1, y2); if ((x2 - x1) > 0 && (y2 - y1) > 0) { /* Copy the area from the backing store to the drawable */ pixel_region_init (&srcPR, layer->fs.backing_store, (x1 - GIMP_ITEM (layer)->offset_x), (y1 - GIMP_ITEM (layer)->offset_y), (x2 - x1), (y2 - y1), FALSE); pixel_region_init (&destPR, gimp_drawable_get_tiles (layer->fs.drawable), (x1 - offx), (y1 - offy), (x2 - x1), (y2 - y1), TRUE); copy_region (&srcPR, &destPR); } }
void gimp_item_get_preview_size (GimpViewable *viewable, gint size, gboolean is_popup, gboolean dot_for_dot, gint *width, gint *height) { GimpItem *item = GIMP_ITEM (viewable); GimpImage *image = gimp_item_get_image (item); if (image && ! image->gimp->config->layer_previews && ! is_popup) { *width = size; *height = size; return; } if (image && ! is_popup) { gdouble xres; gdouble yres; gimp_image_get_resolution (image, &xres, &yres); gimp_viewable_calc_preview_size (gimp_image_get_width (image), gimp_image_get_height (image), size, size, dot_for_dot, xres, yres, width, height, NULL); } else { gimp_viewable_calc_preview_size (gimp_item_width (item), gimp_item_height (item), size, size, dot_for_dot, 1.0, 1.0, width, height, NULL); } }
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_push_undo (channel, undo_desc); /* if applicable, replace the current selection */ if (op == GIMP_CHANNEL_OP_REPLACE) gimp_channel_clear (channel, NULL, FALSE); if (feather || op == GIMP_CHANNEL_OP_INTERSECT) { GimpItem *item = GIMP_ITEM (channel); GimpChannel *add_on2; add_on2 = gimp_channel_new_mask (gimp_item_get_image (item), gimp_item_width (item), gimp_item_height (item)); gimp_channel_combine_mask (add_on2, add_on, GIMP_CHANNEL_OP_ADD, offset_x, offset_y); if (feather) gimp_channel_feather (add_on2, feather_radius_x, feather_radius_y, FALSE /* no undo */); gimp_channel_combine_mask (channel, add_on2, op, 0, 0); g_object_unref (add_on2); } else { gimp_channel_combine_mask (channel, add_on, op, offset_x, offset_y); } }
/* * Position the dropped item in the middle of the viewport. */ static void gimp_display_shell_dnd_position_item (GimpDisplayShell *shell, GimpItem *item) { gint x, y; gint width, height; gint off_x, off_y; gimp_display_shell_untransform_viewport (shell, &x, &y, &width, &height); gimp_item_offsets (item, &off_x, &off_y); off_x = x + (width - gimp_item_width (item)) / 2 - off_x; off_y = y + (height - gimp_item_height (item)) / 2 - off_y; gimp_item_translate (item, off_x, off_y, FALSE); }
void gimp_channel_select_scan_convert (GimpChannel *channel, const gchar *undo_desc, GimpScanConvert *scan_convert, gint offset_x, gint offset_y, GimpChannelOps op, gboolean antialias, gboolean feather, gdouble feather_radius_x, gdouble feather_radius_y, gboolean push_undo) { GimpItem *item; GimpChannel *add_on; 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 (scan_convert != NULL); if (push_undo) gimp_channel_push_undo (channel, undo_desc); /* if applicable, replace the current selection */ if (op == GIMP_CHANNEL_OP_REPLACE) gimp_channel_clear (channel, NULL, FALSE); item = GIMP_ITEM (channel); add_on = gimp_channel_new_mask (gimp_item_get_image (item), gimp_item_width (item), gimp_item_height (item)); gimp_scan_convert_render (scan_convert, gimp_drawable_get_tiles (GIMP_DRAWABLE (add_on)), offset_x, offset_y, antialias); if (feather) gimp_channel_feather (add_on, feather_radius_x, feather_radius_y, FALSE /* no undo */); gimp_channel_combine_mask (channel, add_on, op, 0, 0); g_object_unref (add_on); }
void gimp_channel_select_alpha (GimpChannel *channel, GimpDrawable *drawable, GimpChannelOps op, gboolean feather, gdouble feather_radius_x, gdouble feather_radius_y) { GimpItem *item; GimpChannel *add_on; gint off_x, off_y; 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)); item = GIMP_ITEM (channel); if (gimp_drawable_has_alpha (drawable)) { add_on = gimp_channel_new_from_alpha (gimp_item_get_image (item), drawable, NULL, NULL); } else { /* no alpha is equivalent to completely opaque alpha, * so simply select the whole layer's extents. --mitch */ add_on = gimp_channel_new_mask (gimp_item_get_image (item), gimp_item_width (GIMP_ITEM (drawable)), gimp_item_height (GIMP_ITEM (drawable))); gimp_channel_all (add_on, FALSE); } gimp_item_offsets (GIMP_ITEM (drawable), &off_x, &off_y); gimp_channel_select_channel (channel, _("Alpha to Selection"), add_on, off_x, off_y, op, feather, feather_radius_x, feather_radius_y); g_object_unref (add_on); }
TempBuf * 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; 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_width (item), NULL); g_return_val_if_fail ((src_y + src_height) <= gimp_item_height (item), NULL); image = gimp_item_get_image (item); if (! image->gimp->config->layer_previews) return NULL; if (GIMP_IMAGE_TYPE_BASE_TYPE (gimp_drawable_type (drawable)) == GIMP_INDEXED) return gimp_drawable_indexed_preview (drawable, gimp_image_get_colormap (image), src_x, src_y, src_width, src_height, dest_width, dest_height); return tile_manager_get_sub_preview (gimp_drawable_get_tiles (drawable), src_x, src_y, src_width, src_height, dest_width, dest_height); }
/** * gimp_item_check_scaling: * @item: Item to check * @new_width: proposed width of item, in pixels * @new_height: proposed height of item, in pixels * * Scales item dimensions, then snaps them to pixel centers * * Returns: #FALSE if any dimension reduces to zero as a result * of this; otherwise, returns #TRUE. **/ gboolean gimp_item_check_scaling (const GimpItem *item, gint new_width, gint new_height) { GimpImage *image; gdouble img_scale_w; gdouble img_scale_h; gint new_item_width; gint new_item_height; g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE); image = gimp_item_get_image (item); img_scale_w = ((gdouble) new_width / (gdouble) gimp_image_get_width (image)); img_scale_h = ((gdouble) new_height / (gdouble) gimp_image_get_height (image)); new_item_width = ROUND (img_scale_w * (gdouble) gimp_item_width (item)); new_item_height = ROUND (img_scale_h * (gdouble) gimp_item_height (item)); return (new_item_width > 0 && new_item_height > 0); }
const BoundSeg * floating_sel_boundary (GimpLayer *layer, gint *n_segs) { PixelRegion bPR; gint i; g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); g_return_val_if_fail (gimp_layer_is_floating_sel (layer), NULL); g_return_val_if_fail (n_segs != NULL, NULL); if (layer->fs.boundary_known == FALSE) { gint width, height; gint off_x, off_y; width = gimp_item_width (GIMP_ITEM (layer)); height = gimp_item_height (GIMP_ITEM (layer)); gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); if (layer->fs.segs) g_free (layer->fs.segs); if (gimp_drawable_has_alpha (GIMP_DRAWABLE (layer))) { /* find the segments */ pixel_region_init (&bPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (layer)), 0, 0, width, height, FALSE); layer->fs.segs = boundary_find (&bPR, BOUNDARY_WITHIN_BOUNDS, 0, 0, width, height, BOUNDARY_HALF_WAY, &layer->fs.num_segs); /* offset the segments */ for (i = 0; i < layer->fs.num_segs; i++) { layer->fs.segs[i].x1 += off_x; layer->fs.segs[i].y1 += off_y; layer->fs.segs[i].x2 += off_x; layer->fs.segs[i].y2 += off_y; } } else { layer->fs.num_segs = 4; layer->fs.segs = g_new0 (BoundSeg, 4); /* top */ layer->fs.segs[0].x1 = off_x; layer->fs.segs[0].y1 = off_y; layer->fs.segs[0].x2 = off_x + width; layer->fs.segs[0].y2 = off_y; /* left */ layer->fs.segs[1].x1 = off_x; layer->fs.segs[1].y1 = off_y; layer->fs.segs[1].x2 = off_x; layer->fs.segs[1].y2 = off_y + height; /* right */ layer->fs.segs[2].x1 = off_x + width; layer->fs.segs[2].y1 = off_y; layer->fs.segs[2].x2 = off_x + width; layer->fs.segs[2].y2 = off_y + height; /* bottom */ layer->fs.segs[3].x1 = off_x; layer->fs.segs[3].y1 = off_y + height; layer->fs.segs[3].x2 = off_x + width; layer->fs.segs[3].y2 = off_y + height; } layer->fs.boundary_known = TRUE; } *n_segs = layer->fs.num_segs; return layer->fs.segs; }
static void gimp_display_shell_drop_drawable (GtkWidget *widget, gint x, gint y, GimpViewable *viewable, gpointer data) { GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (data); GimpImage *image = shell->display->image; GType new_type; GimpItem *new_item; gboolean new_image = FALSE; GIMP_LOG (DND, NULL); if (shell->display->gimp->busy) return; if (! image) { GimpImage *src_image = gimp_item_get_image (GIMP_ITEM (viewable)); GimpDrawable *drawable = GIMP_DRAWABLE (viewable); GimpImageBaseType type; gdouble xres; gdouble yres; type = GIMP_IMAGE_TYPE_BASE_TYPE (gimp_drawable_type (drawable)); image = gimp_create_image (shell->display->gimp, gimp_item_width (GIMP_ITEM (viewable)), gimp_item_height (GIMP_ITEM (viewable)), type, TRUE); gimp_image_undo_disable (image); if (type == GIMP_INDEXED) gimp_image_set_colormap (image, gimp_image_get_colormap (src_image), gimp_image_get_colormap_size (src_image), FALSE); gimp_image_get_resolution (src_image, &xres, &yres); gimp_image_set_resolution (image, xres, yres); gimp_image_set_unit (image, gimp_image_get_unit (src_image)); gimp_create_display (image->gimp, image, GIMP_UNIT_PIXEL, 1.0); g_object_unref (image); new_image = TRUE; } if (GIMP_IS_LAYER (viewable)) new_type = G_TYPE_FROM_INSTANCE (viewable); else new_type = GIMP_TYPE_LAYER; new_item = gimp_item_convert (GIMP_ITEM (viewable), image, new_type); if (new_item) { GimpLayer *new_layer = GIMP_LAYER (new_item); gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_EDIT_PASTE, _("Drop New Layer")); if (! new_image) gimp_display_shell_dnd_position_item (shell, new_item); gimp_item_set_visible (new_item, TRUE, FALSE); gimp_item_set_linked (new_item, FALSE, FALSE); gimp_image_add_layer (image, new_layer, -1); gimp_image_undo_group_end (image); gimp_display_shell_dnd_flush (shell, image); } if (new_image) gimp_image_undo_enable (image); }
/* * some rather complex logic here. If the user clicks without modifiers, * then we start a new list, and use the first object in it as reference. * If the user clicks using Shift, or draws a rubber-band box, then * we add objects to the list, but do not specify which one should * be used as reference. */ static void gimp_align_tool_button_release (GimpTool *tool, GimpCoords *coords, guint32 time, GdkModifierType state, GimpButtonReleaseType release_type, GimpDisplay *display) { GimpAlignTool *align_tool = GIMP_ALIGN_TOOL (tool); GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (display->shell); GObject *object = NULL; GimpImage *image = display->image; gint i; gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool)); if (release_type == GIMP_BUTTON_RELEASE_CANCEL) { align_tool->x1 = align_tool->x0; align_tool->y1 = align_tool->y0; gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool)); return; } if (! (state & GDK_SHIFT_MASK)) /* start a new list */ { clear_all_selected_objects (align_tool); align_tool->set_reference = FALSE; } /* if mouse has moved less than EPSILON pixels since button press, select the nearest thing, otherwise make a rubber-band rectangle */ if (hypot (coords->x - align_tool->x0, coords->y - align_tool->y0) < EPSILON) { GimpVectors *vectors; GimpGuide *guide; GimpLayer *layer; gint snap_distance; snap_distance = GIMP_DISPLAY_CONFIG (display->image->gimp->config)->snap_distance; if (gimp_draw_tool_on_vectors (GIMP_DRAW_TOOL (tool), display, coords, snap_distance, snap_distance, NULL, NULL, NULL, NULL, NULL, &vectors)) { object = G_OBJECT (vectors); } else if (gimp_display_shell_get_show_guides (shell) && (guide = gimp_image_find_guide (display->image, coords->x, coords->y, FUNSCALEX (shell, snap_distance), FUNSCALEY (shell, snap_distance)))) { object = G_OBJECT (guide); } else { if ((layer = select_layer_by_coords (display->image, coords->x, coords->y))) { object = G_OBJECT (layer); } } if (object) { if (! g_list_find (align_tool->selected_objects, object)) { align_tool->selected_objects = g_list_append (align_tool->selected_objects, object); g_signal_connect (object, "removed", G_CALLBACK (clear_selected_object), (gpointer) align_tool); /* if an object has been selected using unmodified click, * it should be used as the reference */ if (! (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) align_tool->set_reference = TRUE; } } } else /* FIXME: look for vectors too */ { gint X0 = MIN (coords->x, align_tool->x0); gint X1 = MAX (coords->x, align_tool->x0); gint Y0 = MIN (coords->y, align_tool->y0); gint Y1 = MAX (coords->y, align_tool->y0); GList *list; for (list = GIMP_LIST (image->layers)->list; list; list = g_list_next (list)) { GimpLayer *layer = list->data; gint x0, y0, x1, y1; if (! gimp_item_get_visible (GIMP_ITEM (layer))) continue; gimp_item_offsets (GIMP_ITEM (layer), &x0, &y0); x1 = x0 + gimp_item_width (GIMP_ITEM (layer)); y1 = y0 + gimp_item_height (GIMP_ITEM (layer)); if (x0 < X0 || y0 < Y0 || x1 > X1 || y1 > Y1) continue; if (g_list_find (align_tool->selected_objects, layer)) continue; align_tool->selected_objects = g_list_append (align_tool->selected_objects, layer); g_signal_connect (layer, "removed", G_CALLBACK (clear_selected_object), (gpointer) align_tool); } } for (i = 0; i < ALIGN_TOOL_NUM_BUTTONS; i++) gtk_widget_set_sensitive (align_tool->button[i], (align_tool->selected_objects != NULL)); align_tool->x1 = align_tool->x0; align_tool->y1 = align_tool->y0; gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool)); }
static void gimp_align_tool_draw (GimpDrawTool *draw_tool) { GimpAlignTool *align_tool = GIMP_ALIGN_TOOL (draw_tool); GList *list; gint x, y, w, h; /* draw rubber-band rectangle */ x = MIN (align_tool->x1, align_tool->x0); y = MIN (align_tool->y1, align_tool->y0); w = MAX (align_tool->x1, align_tool->x0) - x; h = MAX (align_tool->y1, align_tool->y0) - y; gimp_draw_tool_draw_rectangle (draw_tool, FALSE, x, y,w, h, FALSE); for (list = g_list_first (align_tool->selected_objects); list; list = g_list_next (list)) { if (GIMP_IS_ITEM (list->data)) { GimpItem *item = GIMP_ITEM (list->data); if (GIMP_IS_VECTORS (list->data)) { gdouble x1_f, y1_f, x2_f, y2_f; gimp_vectors_bounds (GIMP_VECTORS (item), &x1_f, &y1_f, &x2_f, &y2_f); x = ROUND (x1_f); y = ROUND (y1_f); w = ROUND (x2_f - x1_f); h = ROUND (y2_f - y1_f); } else { gimp_item_offsets (item, &x, &y); w = gimp_item_width (item); h = gimp_item_height (item); } gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE, x, y, MARKER_WIDTH, MARKER_WIDTH, GTK_ANCHOR_NORTH_WEST, FALSE); gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE, x + w, y, MARKER_WIDTH, MARKER_WIDTH, GTK_ANCHOR_NORTH_EAST, FALSE); gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE, x, y + h, MARKER_WIDTH, MARKER_WIDTH, GTK_ANCHOR_SOUTH_WEST, FALSE); gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE, x + w, y + h, MARKER_WIDTH, MARKER_WIDTH, GTK_ANCHOR_SOUTH_EAST, FALSE); } else if (GIMP_IS_GUIDE (list->data)) { GimpGuide *guide = GIMP_GUIDE (list->data); GimpImage *image = GIMP_TOOL (draw_tool)->display->image; gint x, y; gint w, h; switch (gimp_guide_get_orientation (guide)) { case GIMP_ORIENTATION_VERTICAL: x = gimp_guide_get_position (guide); h = gimp_image_get_height (image); gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE, x, h, MARKER_WIDTH, MARKER_WIDTH, GTK_ANCHOR_SOUTH, FALSE); gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE, x, 0, MARKER_WIDTH, MARKER_WIDTH, GTK_ANCHOR_NORTH, FALSE); break; case GIMP_ORIENTATION_HORIZONTAL: y = gimp_guide_get_position (guide); w = gimp_image_get_width (image); gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE, w, y, MARKER_WIDTH, MARKER_WIDTH, GTK_ANCHOR_EAST, FALSE); gimp_draw_tool_draw_handle (draw_tool, GIMP_HANDLE_FILLED_SQUARE, 0, y, MARKER_WIDTH, MARKER_WIDTH, GTK_ANCHOR_WEST, FALSE); break; default: break; } } } }
void gimp_image_crop (GimpImage *image, GimpContext *context, gint x1, gint y1, gint x2, gint y2, gboolean active_layer_only, gboolean crop_layers) { gint width, height; gint previous_width, previous_height; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (GIMP_IS_CONTEXT (context)); previous_width = gimp_image_get_width (image); previous_height = gimp_image_get_height (image); width = x2 - x1; height = y2 - y1; /* Make sure new width and height are non-zero */ if (width < 1 || height < 1) return; gimp_set_busy (image->gimp); if (active_layer_only) { GimpLayer *layer; gint off_x, off_y; layer = gimp_image_get_active_layer (image); gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); off_x -= x1; off_y -= y1; gimp_item_resize (GIMP_ITEM (layer), context, width, height, off_x, off_y); } else { GimpItem *item; GList *list; g_object_freeze_notify (G_OBJECT (image)); if (crop_layers) gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CROP, C_("command", "Crop Image")); else gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_RESIZE, _("Resize Image")); /* Push the image size to the stack */ gimp_image_undo_push_image_size (image, NULL, x1, y1, width, height); /* Set the new width and height */ g_object_set (image, "width", width, "height", height, NULL); /* Resize all channels */ for (list = GIMP_LIST (image->channels)->list; list; list = g_list_next (list)) { item = (GimpItem *) list->data; gimp_item_resize (item, context, width, height, -x1, -y1); } /* Resize all vectors */ for (list = GIMP_LIST (image->vectors)->list; list; list = g_list_next (list)) { item = (GimpItem *) list->data; gimp_item_resize (item, context, width, height, -x1, -y1); } /* Don't forget the selection mask! */ gimp_item_resize (GIMP_ITEM (gimp_image_get_mask (image)), context, width, height, -x1, -y1); /* crop all layers */ list = GIMP_LIST (image->layers)->list; while (list) { item = (GimpItem *) list->data; list = g_list_next (list); gimp_item_translate (item, -x1, -y1, TRUE); if (crop_layers) { gint off_x, off_y; gint lx1, ly1, lx2, ly2; gimp_item_offsets (item, &off_x, &off_y); lx1 = CLAMP (off_x, 0, gimp_image_get_width (image)); ly1 = CLAMP (off_y, 0, gimp_image_get_height (image)); lx2 = CLAMP (gimp_item_width (item) + off_x, 0, gimp_image_get_width (image)); ly2 = CLAMP (gimp_item_height (item) + off_y, 0, gimp_image_get_height (image)); width = lx2 - lx1; height = ly2 - ly1; if (width > 0 && height > 0) gimp_item_resize (item, context, width, height, -(lx1 - off_x), -(ly1 - off_y)); else gimp_image_remove_layer (image, GIMP_LAYER (item)); } } /* Reposition or remove all guides */ list = gimp_image_get_guides (image); while (list) { GimpGuide *guide = list->data; gboolean remove_guide = FALSE; gint position = gimp_guide_get_position (guide); list = g_list_next (list); switch (gimp_guide_get_orientation (guide)) { case GIMP_ORIENTATION_HORIZONTAL: if ((position < y1) || (position > y2)) remove_guide = TRUE; else position -= y1; break; case GIMP_ORIENTATION_VERTICAL: if ((position < x1) || (position > x2)) remove_guide = TRUE; else position -= x1; break; default: break; } if (remove_guide) gimp_image_remove_guide (image, guide, TRUE); else if (position != gimp_guide_get_position (guide)) gimp_image_move_guide (image, guide, position, TRUE); } /* Reposition or remove sample points */ list = gimp_image_get_sample_points (image); while (list) { GimpSamplePoint *sample_point = list->data; gboolean remove_sample_point = FALSE; gint new_x = sample_point->x; gint new_y = sample_point->y; list = g_list_next (list); new_y -= y1; if ((sample_point->y < y1) || (sample_point->y > y2)) remove_sample_point = TRUE; new_x -= x1; if ((sample_point->x < x1) || (sample_point->x > x2)) remove_sample_point = TRUE; if (remove_sample_point) gimp_image_remove_sample_point (image, sample_point, TRUE); else if (new_x != sample_point->x || new_y != sample_point->y) gimp_image_move_sample_point (image, sample_point, new_x, new_y, TRUE); } gimp_image_undo_group_end (image); gimp_image_update (image, 0, 0, gimp_image_get_width (image), gimp_image_get_height (image)); gimp_image_size_changed_detailed (image, -x1, -y1, previous_width, previous_height); g_object_thaw_notify (G_OBJECT (image)); } gimp_unset_busy (image->gimp); }
static GimpLayer * gimp_image_merge_layers (GimpImage *image, GSList *merge_list, GimpContext *context, GimpMergeType merge_type, const gchar *undo_desc) { GList *list; GSList *reverse_list = NULL; PixelRegion src1PR, src2PR, maskPR; PixelRegion *mask; GimpLayer *merge_layer; GimpLayer *layer; GimpLayer *bottom_layer; GimpImageType type; gint count; gint x1, y1, x2, y2; gint x3, y3, x4, y4; CombinationMode operation; gint position; gboolean active[MAX_CHANNELS] = { TRUE, TRUE, TRUE, TRUE }; gint off_x, off_y; gchar *name; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); layer = NULL; type = GIMP_RGBA_IMAGE; x1 = y1 = 0; x2 = y2 = 0; bottom_layer = NULL; /* Get the layer extents */ count = 0; while (merge_list) { layer = merge_list->data; gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); switch (merge_type) { case GIMP_EXPAND_AS_NECESSARY: case GIMP_CLIP_TO_IMAGE: if (! count) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_height (GIMP_ITEM (layer)); } else { if (off_x < x1) x1 = off_x; if (off_y < y1) y1 = off_y; if ((off_x + gimp_item_width (GIMP_ITEM (layer))) > x2) x2 = (off_x + gimp_item_width (GIMP_ITEM (layer))); if ((off_y + gimp_item_height (GIMP_ITEM (layer))) > y2) y2 = (off_y + gimp_item_height (GIMP_ITEM (layer))); } if (merge_type == GIMP_CLIP_TO_IMAGE) { x1 = CLAMP (x1, 0, gimp_image_get_width (image)); y1 = CLAMP (y1, 0, gimp_image_get_height (image)); x2 = CLAMP (x2, 0, gimp_image_get_width (image)); y2 = CLAMP (y2, 0, gimp_image_get_height (image)); } break; case GIMP_CLIP_TO_BOTTOM_LAYER: if (merge_list->next == NULL) { x1 = off_x; y1 = off_y; x2 = off_x + gimp_item_width (GIMP_ITEM (layer)); y2 = off_y + gimp_item_height (GIMP_ITEM (layer)); } break; case GIMP_FLATTEN_IMAGE: if (merge_list->next == NULL) { x1 = 0; y1 = 0; x2 = gimp_image_get_width (image); y2 = gimp_image_get_height (image); } break; } count ++; reverse_list = g_slist_prepend (reverse_list, layer); merge_list = g_slist_next (merge_list); } if ((x2 - x1) == 0 || (y2 - y1) == 0) return NULL; /* Start a merge undo group. */ gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_LAYERS_MERGE, undo_desc); name = g_strdup (gimp_object_get_name (GIMP_OBJECT (layer))); if (merge_type == GIMP_FLATTEN_IMAGE || gimp_drawable_type (GIMP_DRAWABLE (layer)) == GIMP_INDEXED_IMAGE) { guchar bg[4] = { 0, 0, 0, 0 }; type = GIMP_IMAGE_TYPE_FROM_BASE_TYPE (gimp_image_base_type (image)); merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), type, gimp_object_get_name (GIMP_OBJECT (layer)), GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (! merge_layer) { g_warning ("%s: could not allocate merge layer.", G_STRFUNC); return NULL; } GIMP_ITEM (merge_layer)->offset_x = x1; GIMP_ITEM (merge_layer)->offset_y = y1; /* get the background for compositing */ gimp_image_get_background (image, context, gimp_drawable_type (GIMP_DRAWABLE (merge_layer)), bg); /* init the pixel region */ pixel_region_init (&src1PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)), 0, 0, (x2 - x1), (y2 - y1), TRUE); /* set the region to the background color */ color_region (&src1PR, bg); position = 0; } else { /* The final merged layer inherits the name of the bottom most layer * and the resulting layer has an alpha channel whether or not the * original did. Opacity is set to 100% and the MODE is set to normal. */ merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1), gimp_drawable_type_with_alpha (GIMP_DRAWABLE (layer)), "merged layer", GIMP_OPACITY_OPAQUE, GIMP_NORMAL_MODE); if (!merge_layer) { g_warning ("%s: could not allocate merge layer", G_STRFUNC); return NULL; } GIMP_ITEM (merge_layer)->offset_x = x1; GIMP_ITEM (merge_layer)->offset_y = y1; /* clear the layer */ pixel_region_init (&src1PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)), 0, 0, (x2 - x1), (y2 - y1), TRUE); clear_region (&src1PR); /* Find the index in the layer list of the bottom layer--we need this * in order to add the final, merged layer to the layer list correctly */ layer = reverse_list->data; position = gimp_container_num_children (image->layers) - gimp_container_get_child_index (image->layers, GIMP_OBJECT (layer)); } bottom_layer = layer; /* Copy the tattoo and parasites of the bottom layer to the new layer */ gimp_item_set_tattoo (GIMP_ITEM (merge_layer), gimp_item_get_tattoo (GIMP_ITEM (bottom_layer))); g_object_unref (GIMP_ITEM (merge_layer)->parasites); GIMP_ITEM (merge_layer)->parasites = gimp_parasite_list_copy (GIMP_ITEM (bottom_layer)->parasites); while (reverse_list) { GimpLayerModeEffects mode; layer = reverse_list->data; /* determine what sort of operation is being attempted and * if it's actually legal... */ operation = gimp_image_merge_layers_get_operation (merge_layer, layer); if (operation == -1) { gimp_layer_add_alpha (layer); /* try again ... */ operation = gimp_image_merge_layers_get_operation (merge_layer, layer); } if (operation == -1) { g_warning ("%s: attempting to merge incompatible layers.", G_STRFUNC); return NULL; } gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); x3 = CLAMP (off_x, x1, x2); y3 = CLAMP (off_y, y1, y2); x4 = CLAMP (off_x + gimp_item_width (GIMP_ITEM (layer)), x1, x2); y4 = CLAMP (off_y + gimp_item_height (GIMP_ITEM (layer)), y1, y2); /* configure the pixel regions */ pixel_region_init (&src1PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (merge_layer)), (x3 - x1), (y3 - y1), (x4 - x3), (y4 - y3), TRUE); pixel_region_init (&src2PR, gimp_drawable_get_tiles (GIMP_DRAWABLE (layer)), (x3 - off_x), (y3 - off_y), (x4 - x3), (y4 - y3), FALSE); if (gimp_layer_get_mask (layer) && gimp_layer_mask_get_apply (layer->mask)) { TileManager *tiles; tiles = gimp_drawable_get_tiles (GIMP_DRAWABLE (layer->mask)); pixel_region_init (&maskPR, tiles, (x3 - off_x), (y3 - off_y), (x4 - x3), (y4 - y3), FALSE); mask = &maskPR; } else { mask = NULL; } /* DISSOLVE_MODE is special since it is the only mode that does not * work on the projection with the lower layer, but only locally on * the layers alpha channel. */ mode = gimp_layer_get_mode (layer); if (layer == bottom_layer && mode != GIMP_DISSOLVE_MODE) mode = GIMP_NORMAL_MODE; combine_regions (&src1PR, &src2PR, &src1PR, mask, NULL, gimp_layer_get_opacity (layer) * 255.999, mode, active, operation); gimp_image_remove_layer (image, layer); reverse_list = g_slist_next (reverse_list); } g_slist_free (reverse_list); /* if the type is flatten, remove all the remaining layers */ if (merge_type == GIMP_FLATTEN_IMAGE) { list = GIMP_LIST (image->layers)->list; while (list) { layer = list->data; list = g_list_next (list); gimp_image_remove_layer (image, layer); } gimp_image_add_layer (image, merge_layer, position); } else { /* Add the layer to the image */ gimp_image_add_layer (image, merge_layer, gimp_container_num_children (image->layers) - position + 1); } /* set the name after the original layers have been removed so we * don't end up with #2 appended to the name */ gimp_object_take_name (GIMP_OBJECT (merge_layer), name); gimp_item_set_visible (GIMP_ITEM (merge_layer), TRUE, TRUE); /* End the merge undo group */ gimp_image_undo_group_end (image); gimp_drawable_update (GIMP_DRAWABLE (merge_layer), 0, 0, gimp_item_width (GIMP_ITEM (merge_layer)), gimp_item_height (GIMP_ITEM (merge_layer))); return merge_layer; }
GtkWidget * resize_dialog_new (GimpViewable *viewable, GimpContext *context, const gchar *title, const gchar *role, GtkWidget *parent, GimpHelpFunc help_func, const gchar *help_id, GimpUnit unit, GimpResizeCallback callback, gpointer user_data) { GtkWidget *dialog; GtkWidget *main_vbox; GtkWidget *vbox; GtkWidget *abox; GtkWidget *frame; GtkWidget *button; GtkWidget *spinbutton; GtkWidget *entry; GtkObject *adjustment; GdkPixbuf *pixbuf; ResizeDialog *private; GimpImage *image = NULL; const gchar *text = NULL; gint width, height; gdouble xres, yres; g_return_val_if_fail (GIMP_IS_VIEWABLE (viewable), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (callback != NULL, NULL); if (GIMP_IS_IMAGE (viewable)) { image = GIMP_IMAGE (viewable); width = gimp_image_get_width (image); height = gimp_image_get_height (image); text = _("Canvas Size"); } else if (GIMP_IS_ITEM (viewable)) { GimpItem *item = GIMP_ITEM (viewable); image = gimp_item_get_image (item); width = gimp_item_width (item); height = gimp_item_height (item); text = _("Layer Size"); } else { g_return_val_if_reached (NULL); } dialog = gimp_viewable_dialog_new (viewable, context, title, role, GIMP_STOCK_RESIZE, title, parent, help_func, help_id, GIMP_STOCK_RESET, RESPONSE_RESET, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GIMP_STOCK_RESIZE, GTK_RESPONSE_OK, NULL); gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog), RESPONSE_RESET, GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1); private = g_slice_new0 (ResizeDialog);
static gboolean gimp_smudge_start (GimpPaintCore *paint_core, GimpDrawable *drawable, GimpPaintOptions *paint_options) { GimpSmudge *smudge = GIMP_SMUDGE (paint_core); GimpImage *image; TempBuf *area; PixelRegion srcPR; gint bytes; gint x, y, w, h; image = gimp_item_get_image (GIMP_ITEM (drawable)); if (gimp_drawable_is_indexed (drawable)) return FALSE; area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options); if (! area) return FALSE; /* adjust the x and y coordinates to the upper left corner of the brush */ gimp_smudge_brush_coords (paint_core, &x, &y, &w, &h); /* Allocate the accumulation buffer */ bytes = gimp_drawable_bytes (drawable); smudge->accum_data = g_malloc (w * h * bytes); /* If clipped, prefill the smudge buffer with the color at the * brush position. */ if (x != area->x || y != area->y || w != area->width || h != area->height) { guchar fill[4]; gimp_pickable_get_pixel_at (GIMP_PICKABLE (drawable), CLAMP ((gint) paint_core->cur_coords.x, 0, gimp_item_width (GIMP_ITEM (drawable)) - 1), CLAMP ((gint) paint_core->cur_coords.y, 0, gimp_item_height (GIMP_ITEM (drawable)) - 1), fill); pixel_region_init_data (&srcPR, smudge->accum_data, bytes, bytes * w, 0, 0, w, h); color_region (&srcPR, fill); } pixel_region_init (&srcPR, gimp_drawable_get_tiles (drawable), area->x, area->y, area->width, area->height, FALSE); pixel_region_init_data (&smudge->accumPR, smudge->accum_data, bytes, bytes * w, area->x - x, area->y - y, area->width, area->height); /* copy the region under the original painthit. */ copy_region (&srcPR, &smudge->accumPR); pixel_region_init_data (&smudge->accumPR, smudge->accum_data, bytes, bytes * w, area->x - x, area->y - y, area->width, area->height); return TRUE; }
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); }