void gimp_paint_core_finish (GimpPaintCore *core, GimpDrawable *drawable, gboolean push_undo) { GimpImage *image; 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))); if (core->stroke_buffer) { g_array_free (core->stroke_buffer, TRUE); core->stroke_buffer = NULL; } image = gimp_item_get_image (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)) { gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable)); return; } if (push_undo) { gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT, core->undo_desc); GIMP_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL); gimp_drawable_push_undo (drawable, NULL, core->x1, core->y1, core->x2 - core->x1, core->y2 - core->y1, core->undo_tiles, TRUE); gimp_image_undo_group_end (image); } tile_manager_unref (core->undo_tiles); core->undo_tiles = NULL; if (core->saved_proj_tiles) { tile_manager_unref (core->saved_proj_tiles); core->saved_proj_tiles = NULL; } gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable)); }
static void gimp_operation_tile_source_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { GimpOperationTileSource *self = GIMP_OPERATION_TILE_SOURCE (object); switch (property_id) { case PROP_TILE_MANAGER: if (self->tile_manager) tile_manager_unref (self->tile_manager); self->tile_manager = g_value_dup_boxed (value); break; case PROP_LINEAR: self->linear = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
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)) { gimp_paint_core_copy_valid_tiles (core->undo_tiles, gimp_drawable_get_tiles (drawable), x, y, width, height); } tile_manager_unref (core->undo_tiles); core->undo_tiles = NULL; if (core->saved_proj_tiles) { tile_manager_unref (core->saved_proj_tiles); core->saved_proj_tiles = NULL; } gimp_drawable_update (drawable, x, y, width, height); gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable)); }
void gimp_paint_core_cleanup (GimpPaintCore *core) { g_return_if_fail (GIMP_IS_PAINT_CORE (core)); if (core->undo_tiles) { tile_manager_unref (core->undo_tiles); core->undo_tiles = NULL; } if (core->saved_proj_tiles) { tile_manager_unref (core->saved_proj_tiles); core->saved_proj_tiles = NULL; } if (core->canvas_tiles) { tile_manager_unref (core->canvas_tiles); core->canvas_tiles = NULL; } if (core->orig_buf) { temp_buf_free (core->orig_buf); core->orig_buf = NULL; } if (core->orig_proj_buf) { temp_buf_free (core->orig_proj_buf); core->orig_proj_buf = NULL; } if (core->canvas_buf) { temp_buf_free (core->canvas_buf); core->canvas_buf = NULL; } }
/** * tile_pyramid_destroy: * @pyramid: a #TilePyramid * * Destroys resources allocated for @pyramid and unrefs all contained * tile-managers. **/ void tile_pyramid_destroy (TilePyramid *pyramid) { gint level; g_return_if_fail (pyramid != NULL); for (level = 0; level <= pyramid->top_level; level++) tile_manager_unref (pyramid->tiles[level]); g_slice_free (TilePyramid, pyramid); }
static void gimp_buffer_finalize (GObject *object) { GimpBuffer *buffer = GIMP_BUFFER (object); if (buffer->tiles) { tile_manager_unref (buffer->tiles); buffer->tiles = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gimp_operation_tile_source_finalize (GObject *object) { GimpOperationTileSource *self = GIMP_OPERATION_TILE_SOURCE (object); if (self->tile_manager) { tile_manager_unref (self->tile_manager); self->tile_manager = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); }
GimpBuffer * gimp_buffer_new_from_pixbuf (GdkPixbuf *pixbuf, const gchar *name, gint offset_x, gint offset_y) { GimpBuffer *buffer; TileManager *tiles; guchar *pixels; PixelRegion destPR; gint width; gint height; gint rowstride; gint channels; gint y; g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); g_return_val_if_fail (name != NULL, NULL); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); channels = gdk_pixbuf_get_n_channels (pixbuf); tiles = tile_manager_new (width, height, channels); pixel_region_init (&destPR, tiles, 0, 0, width, height, TRUE); for (y = 0, pixels = gdk_pixbuf_get_pixels (pixbuf); y < height; y++, pixels += rowstride) { pixel_region_set_row (&destPR, 0, y, width, pixels); } buffer = gimp_buffer_new (tiles, name, offset_x, offset_y, FALSE); tile_manager_unref (tiles); return buffer; }
void gimp_drawable_bucket_fill_full (GimpDrawable *drawable, GimpBucketFillMode fill_mode, gint paint_mode, gdouble opacity, gboolean do_seed_fill, gboolean fill_transparent, GimpSelectCriterion fill_criterion, gdouble threshold, gboolean sample_merged, gdouble x, gdouble y, const GimpRGB *color, GimpPattern *pattern) { GimpImage *image; TileManager *buf_tiles; PixelRegion bufPR, maskPR; GimpChannel *mask = NULL; gint bytes; gint x1, y1, x2, y2; guchar col[MAX_CHANNELS]; TempBuf *pat_buf = NULL; gboolean new_buf = FALSE; gboolean selection; g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (fill_mode != GIMP_PATTERN_BUCKET_FILL || GIMP_IS_PATTERN (pattern)); g_return_if_fail (fill_mode == GIMP_PATTERN_BUCKET_FILL || color != NULL); image = gimp_item_get_image (GIMP_ITEM (drawable)); bytes = gimp_drawable_bytes (drawable); selection = gimp_item_mask_bounds (GIMP_ITEM (drawable), &x1, &y1, &x2, &y2); if ((x1 == x2) || (y1 == y2)) return; if (fill_mode == GIMP_FG_BUCKET_FILL || fill_mode == GIMP_BG_BUCKET_FILL) { guchar tmp_col[MAX_CHANNELS]; gimp_rgb_get_uchar (color, &tmp_col[RED], &tmp_col[GREEN], &tmp_col[BLUE]); gimp_image_transform_color (image, gimp_drawable_type (drawable), col, GIMP_RGB, tmp_col); col[gimp_drawable_bytes_with_alpha (drawable) - 1] = OPAQUE_OPACITY; } else if (fill_mode == GIMP_PATTERN_BUCKET_FILL) { pat_buf = gimp_image_transform_temp_buf (image, gimp_drawable_type (drawable), pattern->mask, &new_buf); } else { g_warning ("%s: invalid fill_mode passed", G_STRFUNC); return; } gimp_set_busy (image->gimp); /* Do a seed bucket fill...To do this, calculate a new * contiguous region. If there is a selection, calculate the * intersection of this region with the existing selection. */ if (do_seed_fill) { mask = gimp_image_contiguous_region_by_seed (image, drawable, sample_merged, TRUE, (gint) threshold, fill_transparent, fill_criterion, (gint) x, (gint) y); if (selection) { gint off_x = 0; gint off_y = 0; if (! sample_merged) gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y); gimp_channel_combine_mask (mask, gimp_image_get_mask (image), GIMP_CHANNEL_OP_INTERSECT, -off_x, -off_y); } gimp_channel_bounds (mask, &x1, &y1, &x2, &y2); /* make sure we handle the mask correctly if it was sample-merged */ if (sample_merged) { GimpItem *item; gint off_x, off_y; item = GIMP_ITEM (drawable); /* Limit the channel bounds to the drawable's extents */ gimp_item_get_offset (item, &off_x, &off_y); x1 = CLAMP (x1, off_x, (off_x + gimp_item_get_width (item))); y1 = CLAMP (y1, off_y, (off_y + gimp_item_get_height (item))); x2 = CLAMP (x2, off_x, (off_x + gimp_item_get_width (item))); y2 = CLAMP (y2, off_y, (off_y + gimp_item_get_height (item))); pixel_region_init (&maskPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)), x1, y1, (x2 - x1), (y2 - y1), TRUE); /* translate mask bounds to drawable coords */ x1 -= off_x; y1 -= off_y; x2 -= off_x; y2 -= off_y; } else { pixel_region_init (&maskPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)), x1, y1, (x2 - x1), (y2 - y1), TRUE); } /* if the image doesn't have an alpha channel, make sure that * the buf_tiles have. We need the alpha channel to fill with * the region calculated above */ if (! gimp_drawable_has_alpha (drawable)) bytes++; } else if (fill_mode == GIMP_PATTERN_BUCKET_FILL && (pat_buf->bytes == 2 || pat_buf->bytes == 4)) { /* If pattern being applied has an alpha channel, add one to the * buf_tiles. */ if (! gimp_drawable_has_alpha (drawable)) bytes++; } buf_tiles = tile_manager_new ((x2 - x1), (y2 - y1), bytes); pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE); switch (fill_mode) { case GIMP_FG_BUCKET_FILL: case GIMP_BG_BUCKET_FILL: if (mask) color_region_mask (&bufPR, &maskPR, col); else color_region (&bufPR, col); break; case GIMP_PATTERN_BUCKET_FILL: if (mask) pattern_region (&bufPR, &maskPR, pat_buf, x1, y1); else pattern_region (&bufPR, NULL, pat_buf, x1, y1); break; } /* Apply it to the image */ pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), FALSE); gimp_drawable_apply_region (drawable, &bufPR, TRUE, C_("undo-type", "Bucket Fill"), opacity, paint_mode, NULL, NULL, x1, y1); tile_manager_unref (buf_tiles); /* update the image */ gimp_drawable_update (drawable, x1, y1, x2 - x1, y2 - y1); /* free the mask */ if (mask) g_object_unref (mask); if (new_buf) temp_buf_free (pat_buf); gimp_unset_busy (image->gimp); }
static gboolean gimp_text_layer_render (GimpTextLayer *layer) { GimpDrawable *drawable; GimpItem *item; GimpImage *image; GimpTextLayout *layout; gdouble xres; gdouble yres; gint width; gint height; if (! layer->text) return FALSE; drawable = GIMP_DRAWABLE (layer); item = GIMP_ITEM (layer); image = gimp_item_get_image (item); if (gimp_container_is_empty (image->gimp->fonts)) { gimp_message_literal (image->gimp, NULL, GIMP_MESSAGE_ERROR, _("Due to lack of any fonts, " "text functionality is not available.")); return FALSE; } gimp_image_get_resolution (image, &xres, &yres); layout = gimp_text_layout_new (layer->text, xres, yres); g_object_freeze_notify (G_OBJECT (drawable)); if (gimp_text_layout_get_size (layout, &width, &height) && (width != gimp_item_get_width (item) || height != gimp_item_get_height (item))) { TileManager *new_tiles = tile_manager_new (width, height, gimp_drawable_bytes (drawable)); gimp_drawable_set_tiles (drawable, FALSE, NULL, new_tiles, gimp_drawable_type (drawable)); tile_manager_unref (new_tiles); if (gimp_layer_get_mask (GIMP_LAYER (layer))) { GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer)); static GimpContext *unused_eek = NULL; if (! unused_eek) unused_eek = gimp_context_new (image->gimp, "eek", NULL); gimp_item_resize (GIMP_ITEM (mask), unused_eek, width, height, 0, 0); } } if (layer->auto_rename) { GimpItem *item = GIMP_ITEM (layer); gchar *name = NULL; if (layer->text->text) { name = gimp_utf8_strtrim (layer->text->text, 30); } else if (layer->text->markup) { gchar *tmp = gimp_markup_extract_text (layer->text->markup); name = gimp_utf8_strtrim (tmp, 30); g_free (tmp); } if (! name) name = g_strdup (_("Empty Text Layer")); if (gimp_item_is_attached (item)) { gimp_item_tree_rename_item (gimp_item_get_tree (item), item, name, FALSE, NULL); g_free (name); } else { gimp_object_take_name (GIMP_OBJECT (layer), name); } } gimp_text_layer_render_layout (layer, layout); g_object_unref (layout); g_object_thaw_notify (G_OBJECT (drawable)); return (width > 0 && height > 0); }
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); }
gboolean gimp_paint_core_start (GimpPaintCore *core, GimpDrawable *drawable, GimpPaintOptions *paint_options, const GimpCoords *coords, GError **error) { GimpItem *item; 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); 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); 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_tiles) tile_manager_unref (core->undo_tiles); core->undo_tiles = tile_manager_new (gimp_item_get_width (item), gimp_item_get_height (item), gimp_drawable_bytes (drawable)); /* Allocate the saved proj structure */ if (core->saved_proj_tiles) tile_manager_unref (core->saved_proj_tiles); core->saved_proj_tiles = NULL; if (core->use_saved_proj) { GimpImage *image = gimp_item_get_image (item); GimpPickable *pickable = GIMP_PICKABLE (gimp_image_get_projection (image)); TileManager *tiles = gimp_pickable_get_tiles (pickable); core->saved_proj_tiles = tile_manager_new (tile_manager_width (tiles), tile_manager_height (tiles), tile_manager_bpp (tiles)); } /* Allocate the canvas blocks structure */ if (core->canvas_tiles) tile_manager_unref (core->canvas_tiles); core->canvas_tiles = tile_manager_new (gimp_item_get_width (item), gimp_item_get_height (item), 1); /* 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; /* Freeze the drawable preview so that it isn't constantly updated. */ gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable)); return TRUE; }
void floating_sel_store (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)); /* Check the backing store & make sure it has the correct dimensions */ if ((tile_manager_width (layer->fs.backing_store) != gimp_item_width (GIMP_ITEM(layer))) || (tile_manager_height (layer->fs.backing_store) != gimp_item_height (GIMP_ITEM(layer))) || (tile_manager_bpp (layer->fs.backing_store) != gimp_drawable_bytes (layer->fs.drawable))) { /* free the backing store and allocate anew */ tile_manager_unref (layer->fs.backing_store); layer->fs.backing_store = tile_manager_new (GIMP_ITEM (layer)->width, GIMP_ITEM (layer)->height, gimp_drawable_bytes (layer->fs.drawable)); } /* What this function does is save the specified area of the * drawable that this floating selection obscures. We do this so * that it will be possible to subsequently restore the drawable's area */ gimp_item_offsets (GIMP_ITEM (layer->fs.drawable), &offx, &offy); /* Find the minimum area we need to uncover -- in image space */ 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 drawable to the backing store */ pixel_region_init (&srcPR, gimp_drawable_get_tiles (layer->fs.drawable), (x1 - offx), (y1 - offy), (x2 - x1), (y2 - y1), FALSE); pixel_region_init (&destPR, layer->fs.backing_store, (x1 - GIMP_ITEM (layer)->offset_x), (y1 - GIMP_ITEM (layer)->offset_y), (x2 - x1), (y2 - y1), TRUE); copy_region (&srcPR, &destPR); } }
static gboolean gimp_perspective_clone_get_source (GimpSourceCore *source_core, GimpDrawable *drawable, GimpPaintOptions *paint_options, GimpPickable *src_pickable, 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, PixelRegion *srcPR) { GimpPerspectiveClone *clone = GIMP_PERSPECTIVE_CLONE (source_core); GimpPaintCore *paint_core = GIMP_PAINT_CORE (source_core); GimpSourceOptions *options = GIMP_SOURCE_OPTIONS (paint_options); GimpImage *src_image; GimpImage *image; GimpImageType src_type; gint x1d, y1d, x2d, y2d; gdouble x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s; gint xmin, ymin, xmax, ymax; TileManager *src_tiles; TileManager *orig_tiles; PixelRegion origPR; PixelRegion destPR; GimpMatrix3 matrix; gint bytes; src_image = gimp_pickable_get_image (src_pickable); image = gimp_item_get_image (GIMP_ITEM (drawable)); src_type = gimp_pickable_get_image_type (src_pickable); src_tiles = gimp_pickable_get_tiles (src_pickable); /* Destination coordinates that will be painted */ x1d = paint_area->x; y1d = paint_area->y; x2d = paint_area->x + paint_area->width; y2d = paint_area->y + paint_area->height; /* Boundary box for source pixels to copy: Convert all the vertex of * the box to paint in destination area to its correspondent in * source area bearing in mind perspective */ gimp_perspective_clone_get_source_point (clone, x1d, y1d, &x1s, &y1s); gimp_perspective_clone_get_source_point (clone, x1d, y2d, &x2s, &y2s); gimp_perspective_clone_get_source_point (clone, x2d, y1d, &x3s, &y3s); gimp_perspective_clone_get_source_point (clone, x2d, y2d, &x4s, &y4s); xmin = floor (MIN4 (x1s, x2s, x3s, x4s)); ymin = floor (MIN4 (y1s, y2s, y3s, y4s)); xmax = ceil (MAX4 (x1s, x2s, x3s, x4s)); ymax = ceil (MAX4 (y1s, y2s, y3s, y4s)); xmin = CLAMP (xmin - 1, 0, tile_manager_width (src_tiles)); ymin = CLAMP (ymin - 1, 0, tile_manager_height (src_tiles)); xmax = CLAMP (xmax + 1, 0, tile_manager_width (src_tiles)); ymax = CLAMP (ymax + 1, 0, tile_manager_height (src_tiles)); /* if the source area is completely out of the image */ if (!(xmax - xmin) || !(ymax - ymin)) return FALSE; /* If the source image is different from the destination, * then we should copy straight from the source image * to the canvas. * Otherwise, we need a call to get_orig_image to make sure * we get a copy of the unblemished (offset) image */ if (( options->sample_merged && (src_image != image)) || (! options->sample_merged && (source_core->src_drawable != drawable))) { pixel_region_init (&origPR, src_tiles, xmin, ymin, xmax - xmin, ymax - ymin, FALSE); } else { TempBuf *orig; /* get the original image */ if (options->sample_merged) orig = gimp_paint_core_get_orig_proj (paint_core, src_pickable, xmin, ymin, xmax, ymax); else orig = gimp_paint_core_get_orig_image (paint_core, GIMP_DRAWABLE (src_pickable), xmin, ymin, xmax, ymax); pixel_region_init_temp_buf (&origPR, orig, 0, 0, xmax - xmin, ymax - ymin); } /* copy the original image to a tile manager, adding alpha if needed */ bytes = GIMP_IMAGE_TYPE_BYTES (GIMP_IMAGE_TYPE_WITH_ALPHA (src_type)); orig_tiles = tile_manager_new (xmax - xmin, ymax - ymin, bytes); tile_manager_set_offsets (orig_tiles, xmin, ymin); pixel_region_init (&destPR, orig_tiles, 0, 0, xmax - xmin, ymax - ymin, TRUE); if (bytes > origPR.bytes) add_alpha_region (&origPR, &destPR); else copy_region (&origPR, &destPR); clone->src_area = temp_buf_resize (clone->src_area, tile_manager_bpp (orig_tiles), 0, 0, x2d - x1d, y2d - y1d); pixel_region_init_temp_buf (&destPR, clone->src_area, 0, 0, x2d - x1d, y2d - y1d); gimp_perspective_clone_get_matrix (clone, &matrix); gimp_transform_region (src_pickable, GIMP_CONTEXT (paint_options), orig_tiles, &destPR, x1d, y1d, x2d, y2d, &matrix, GIMP_INTERPOLATION_LINEAR, 0, NULL); tile_manager_unref (orig_tiles); pixel_region_init_temp_buf (srcPR, clone->src_area, 0, 0, x2d - x1d, y2d - y1d); return TRUE; }