TileManager * gimp_buffer_to_tiles (GeglBuffer *buffer) { const Babl *format = gegl_buffer_get_format (buffer); TileManager *new_tiles = NULL; GeglNode *source = NULL; GeglNode *sink = NULL; g_return_val_if_fail (buffer != NULL, NULL); /* Setup and process the graph */ new_tiles = tile_manager_new (gegl_buffer_get_width (buffer), gegl_buffer_get_height (buffer), gimp_babl_format_to_legacy_bpp (format)); source = gegl_node_new_child (NULL, "operation", "gegl:buffer-source", "buffer", buffer, NULL); sink = gegl_node_new_child (NULL, "operation", "gimp:tilemanager-sink", "tile-manager", new_tiles, NULL); gegl_node_link_many (source, sink, NULL); gegl_node_process (sink); /* Clenaup */ g_object_unref (sink); g_object_unref (source); return new_tiles; }
GimpBuffer * gimp_buffer_new_from_pixbuf (GdkPixbuf *pixbuf, const gchar *name) { 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); } return gimp_buffer_new (tiles, name, FALSE); }
/** * tile_pyramid_new: * @type: type of pixel data stored in the pyramid * @width: bottom level width * @height: bottom level height * * Creates a new #TilePyramid, managing a set of tile-managers where * each level is a sized-down version of the level below. * * This only works correctly if you set a validate procedure using * tile_pyramid_set_validate_proc() and invalidate areas. With some * small changes, it could be made to work for non-validating tile * managers also. But currently only the projection uses it. * * Only the bottom-most tile-manager is allocated at this point. Upper * levels are created only if they are requested. * * Return value: a newly allocate #TilePyramid **/ TilePyramid * tile_pyramid_new (GimpImageType type, gint width, gint height) { TilePyramid *pyramid; g_return_val_if_fail (width > 0, NULL); g_return_val_if_fail (height > 0, NULL); pyramid = g_slice_new0 (TilePyramid); pyramid->type = type; pyramid->width = width; pyramid->height = height; switch (type) { case GIMP_GRAY_IMAGE: pyramid->bytes = 1; break; case GIMP_GRAYA_IMAGE: pyramid->bytes = 2; break; case GIMP_RGB_IMAGE: pyramid->bytes = 3; break; case GIMP_RGBA_IMAGE: pyramid->bytes = 4; break; case GIMP_INDEXED_IMAGE: case GIMP_INDEXEDA_IMAGE: g_assert_not_reached (); break; } pyramid->tiles[0] = tile_manager_new (width, height, pyramid->bytes); return pyramid; }
void floating_sel_attach (GimpLayer *layer, GimpDrawable *drawable) { GimpImage *image; GimpLayer *floating_sel; g_return_if_fail (GIMP_IS_LAYER (layer)); g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); g_return_if_fail (drawable != GIMP_DRAWABLE (layer)); g_return_if_fail (gimp_item_get_image (GIMP_ITEM (layer)) == gimp_item_get_image (GIMP_ITEM (drawable))); image = gimp_item_get_image (GIMP_ITEM (drawable)); floating_sel = gimp_image_floating_sel (image); /* If there is already a floating selection, anchor it */ if (floating_sel) { floating_sel_anchor (floating_sel); /* if we were pasting to the old floating selection, paste now * to the drawable */ if (drawable == (GimpDrawable *) floating_sel) drawable = gimp_image_get_active_drawable (image); } /* set the drawable and allocate a backing store */ gimp_layer_set_lock_alpha (layer, TRUE, FALSE); layer->fs.drawable = drawable; layer->fs.backing_store = tile_manager_new (GIMP_ITEM (layer)->width, GIMP_ITEM (layer)->height, gimp_drawable_bytes (drawable)); /* add the layer to the image */ gimp_image_add_layer (image, layer, 0); /* store the affected area from the drawable in the backing store */ floating_sel_rigor (layer, TRUE); }
GimpBuffer * gimp_buffer_new (TileManager *tiles, const gchar *name, gboolean copy_pixels) { GimpBuffer *buffer; gint width, height; g_return_val_if_fail (tiles != NULL, NULL); g_return_val_if_fail (name != NULL, NULL); width = tile_manager_width (tiles); height = tile_manager_height (tiles); buffer = g_object_new (GIMP_TYPE_BUFFER, "name", name, NULL); if (copy_pixels) { PixelRegion srcPR, destPR; buffer->tiles = tile_manager_new (width, height, tile_manager_bpp (tiles)); pixel_region_init (&srcPR, tiles, 0, 0, width, height, FALSE); pixel_region_init (&destPR, buffer->tiles, 0, 0, width, height, TRUE); copy_region (&srcPR, &destPR); } else { buffer->tiles = tiles; } return buffer; }
/* This function make sure that levels are allocated up to the level * it returns. The return value may be smaller than the level that * was actually requested. */ static gint tile_pyramid_alloc_levels (TilePyramid *pyramid, gint top_level) { gint level; top_level = MIN (top_level, PYRAMID_MAX_LEVELS - 1); if (top_level <= pyramid->top_level) return top_level; for (level = pyramid->top_level + 1; level <= top_level; level++) { gint width = pyramid->width >> level; gint height = pyramid->height >> level; if (width == 0 || height == 0) return pyramid->top_level; /* There is no use having levels that have the same number of * tiles as the parent level. */ if (width <= TILE_WIDTH / 2 && height <= TILE_HEIGHT / 2) return pyramid->top_level; pyramid->top_level = level; pyramid->tiles[level] = tile_manager_new (width, height, pyramid->bytes); /* Use the level below to validate tiles. */ tile_manager_set_validate_proc (pyramid->tiles[level], (TileValidateProc) tile_pyramid_validate_tile, pyramid->tiles[level - 1]); } return pyramid->top_level; }
void gimp_drawable_real_apply_region (GimpDrawable *drawable, PixelRegion *src2PR, gboolean push_undo, const gchar *undo_desc, gdouble opacity, GimpLayerModeEffects mode, TileManager *src1_tiles, PixelRegion *destPR, gint x, gint y) { GimpItem *item = GIMP_ITEM (drawable); GimpImage *image = gimp_item_get_image (item); GimpChannel *mask = gimp_image_get_mask (image); gint x1, y1, x2, y2; gint offset_x, offset_y; PixelRegion src1PR, my_destPR; CombinationMode operation; gboolean active_components[MAX_CHANNELS]; /* don't apply the mask to itself and don't apply an empty mask */ if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask)) mask = NULL; /* configure the active channel array */ gimp_drawable_get_active_components (drawable, active_components); /* determine what sort of operation is being attempted and * if it's actually legal... */ operation = gimp_image_get_combination_mode (gimp_drawable_type (drawable), src2PR->bytes); if (operation == -1) { g_warning ("%s: illegal parameters.", G_STRFUNC); return; } /* get the layer offsets */ gimp_item_get_offset (item, &offset_x, &offset_y); /* make sure the image application coordinates are within drawable bounds */ x1 = CLAMP (x, 0, gimp_item_get_width (item)); y1 = CLAMP (y, 0, gimp_item_get_height (item)); x2 = CLAMP (x + src2PR->w, 0, gimp_item_get_width (item)); y2 = CLAMP (y + src2PR->h, 0, gimp_item_get_height (item)); if (mask) { GimpItem *mask_item = GIMP_ITEM (mask); /* make sure coordinates are in mask bounds ... * we need to add the layer offset to transform coords * into the mask coordinate system */ x1 = CLAMP (x1, -offset_x, gimp_item_get_width (mask_item) - offset_x); y1 = CLAMP (y1, -offset_y, gimp_item_get_height (mask_item) - offset_y); x2 = CLAMP (x2, -offset_x, gimp_item_get_width (mask_item) - offset_x); y2 = CLAMP (y2, -offset_y, gimp_item_get_height (mask_item) - offset_y); } /* If the calling procedure specified an undo step... */ if (push_undo) { GimpDrawableUndo *undo; gimp_drawable_push_undo (drawable, undo_desc, x1, y1, x2 - x1, y2 - y1, NULL, FALSE); undo = GIMP_DRAWABLE_UNDO (gimp_image_undo_get_fadeable (image)); if (undo) { PixelRegion tmp_srcPR; PixelRegion tmp_destPR; undo->paint_mode = mode; undo->opacity = opacity; undo->src2_tiles = tile_manager_new (x2 - x1, y2 - y1, src2PR->bytes); tmp_srcPR = *src2PR; pixel_region_resize (&tmp_srcPR, src2PR->x + (x1 - x), src2PR->y + (y1 - y), x2 - x1, y2 - y1); pixel_region_init (&tmp_destPR, undo->src2_tiles, 0, 0, x2 - x1, y2 - y1, TRUE); copy_region (&tmp_srcPR, &tmp_destPR); } } /* configure the pixel regions */ /* check if an alternative to using the drawable's data as src1 was * provided... */ if (src1_tiles) { pixel_region_init (&src1PR, src1_tiles, x1, y1, x2 - x1, y2 - y1, FALSE); } else { pixel_region_init (&src1PR, gimp_drawable_get_tiles (drawable), x1, y1, x2 - x1, y2 - y1, FALSE); } /* check if an alternative to using the drawable's data as dest was * provided... */ if (!destPR) { pixel_region_init (&my_destPR, gimp_drawable_get_tiles (drawable), x1, y1, x2 - x1, y2 - y1, TRUE); destPR = &my_destPR; } pixel_region_resize (src2PR, src2PR->x + (x1 - x), src2PR->y + (y1 - y), x2 - x1, y2 - y1); if (mask) { PixelRegion maskPR; pixel_region_init (&maskPR, gimp_drawable_get_tiles (GIMP_DRAWABLE (mask)), x1 + offset_x, y1 + offset_y, x2 - x1, y2 - y1, FALSE); combine_regions (&src1PR, src2PR, destPR, &maskPR, NULL, opacity * 255.999, mode, active_components, operation); } else { combine_regions (&src1PR, src2PR, destPR, NULL, NULL, opacity * 255.999, mode, active_components, operation); } }
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; }