summaryrefslogtreecommitdiffstats
path: root/libgimp/gimpdrawable.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgimp/gimpdrawable.c')
-rw-r--r--libgimp/gimpdrawable.c822
1 files changed, 822 insertions, 0 deletions
diff --git a/libgimp/gimpdrawable.c b/libgimp/gimpdrawable.c
new file mode 100644
index 0000000..5ea1079
--- /dev/null
+++ b/libgimp/gimpdrawable.c
@@ -0,0 +1,822 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpdrawable.c
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#define GIMP_DISABLE_DEPRECATION_WARNINGS
+
+#include "gimp.h"
+
+#include "gimptilebackendplugin.h"
+
+
+#define TILE_WIDTH gimp_tile_width()
+#define TILE_HEIGHT gimp_tile_height()
+
+
+/**
+ * gimp_drawable_get:
+ * @drawable_ID: the ID of the drawable
+ *
+ * This function creates a #GimpDrawable structure for the core
+ * drawable identified by @drawable_ID. The returned structure
+ * contains some basic information about the drawable and can also
+ * hold tile data for transfer to and from the core.
+ *
+ * Note that the name of this function is somewhat misleading, because
+ * it suggests that it simply returns a handle. This is not the case:
+ * if the function is called multiple times, it creates separate tile
+ * lists each time, which will usually produce undesired results.
+ *
+ * When a plug-in has finished working with a drawable, before exiting
+ * it should call gimp_drawable_detach() to make sure that all tile data is
+ * transferred back to the core.
+ *
+ * Return value: a new #GimpDrawable wrapper
+ **/
+GimpDrawable *
+gimp_drawable_get (gint32 drawable_ID)
+{
+ GimpDrawable *drawable;
+ gint width;
+ gint height;
+ gint bpp;
+
+ width = gimp_drawable_width (drawable_ID);
+ height = gimp_drawable_height (drawable_ID);
+ bpp = gimp_drawable_bpp (drawable_ID);
+
+ g_return_val_if_fail (width > 0 && height > 0 && bpp > 0, NULL);
+
+ drawable = g_slice_new0 (GimpDrawable);
+
+ drawable->drawable_id = drawable_ID;
+ drawable->width = width;
+ drawable->height = height;
+ drawable->bpp = bpp;
+ drawable->ntile_rows = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
+ drawable->ntile_cols = (width + TILE_WIDTH - 1) / TILE_WIDTH;
+
+ return drawable;
+}
+
+/**
+ * gimp_drawable_detach:
+ * @drawable: The #GimpDrawable to detach from the core
+ *
+ * This function is called when a plug-in is finished working
+ * with a drawable. It forces all tile data held in the tile
+ * list of the #GimpDrawable to be transferred to the core, and
+ * then frees all associated memory. You must not access the
+ * @drawable after having called gimp_drawable_detach().
+ **/
+void
+gimp_drawable_detach (GimpDrawable *drawable)
+{
+ g_return_if_fail (drawable != NULL);
+
+ gimp_drawable_flush (drawable);
+
+ if (drawable->tiles)
+ g_free (drawable->tiles);
+
+ if (drawable->shadow_tiles)
+ g_free (drawable->shadow_tiles);
+
+ g_slice_free (GimpDrawable, drawable);
+}
+
+/**
+ * gimp_drawable_flush:
+ * @drawable: The #GimpDrawable whose tile data is to be transferred
+ * to the core.
+ *
+ * This function causes all tile data in the tile list of @drawable to be
+ * transferred to the core. It is usually called in situations where a
+ * plug-in acts on a drawable, and then needs to read the results of its
+ * actions. Data transferred back from the core will not generally be valid
+ * unless gimp_drawable_flush() has been called beforehand.
+ **/
+void
+gimp_drawable_flush (GimpDrawable *drawable)
+{
+ GimpTile *tiles;
+ gint n_tiles;
+ gint i;
+
+ g_return_if_fail (drawable != NULL);
+
+ if (drawable->tiles)
+ {
+ tiles = drawable->tiles;
+ n_tiles = drawable->ntile_rows * drawable->ntile_cols;
+
+ for (i = 0; i < n_tiles; i++)
+ if ((tiles[i].ref_count > 0) && tiles[i].dirty)
+ gimp_tile_flush (&tiles[i]);
+ }
+
+ if (drawable->shadow_tiles)
+ {
+ tiles = drawable->shadow_tiles;
+ n_tiles = drawable->ntile_rows * drawable->ntile_cols;
+
+ for (i = 0; i < n_tiles; i++)
+ if ((tiles[i].ref_count > 0) && tiles[i].dirty)
+ gimp_tile_flush (&tiles[i]);
+ }
+
+ /* nuke all references to this drawable from the cache */
+ _gimp_tile_cache_flush_drawable (drawable);
+}
+
+GimpTile *
+gimp_drawable_get_tile (GimpDrawable *drawable,
+ gboolean shadow,
+ gint row,
+ gint col)
+{
+ GimpTile *tiles;
+ guint right_tile;
+ guint bottom_tile;
+ gint n_tiles;
+ gint tile_num;
+ gint i, j, k;
+
+ g_return_val_if_fail (drawable != NULL, NULL);
+
+ if (shadow)
+ tiles = drawable->shadow_tiles;
+ else
+ tiles = drawable->tiles;
+
+ if (! tiles)
+ {
+ n_tiles = drawable->ntile_rows * drawable->ntile_cols;
+ tiles = g_new (GimpTile, n_tiles);
+
+ right_tile = (drawable->width -
+ ((drawable->ntile_cols - 1) * TILE_WIDTH));
+ bottom_tile = (drawable->height -
+ ((drawable->ntile_rows - 1) * TILE_HEIGHT));
+
+ for (i = 0, k = 0; i < drawable->ntile_rows; i++)
+ {
+ for (j = 0; j < drawable->ntile_cols; j++, k++)
+ {
+ tiles[k].bpp = drawable->bpp;
+ tiles[k].tile_num = k;
+ tiles[k].ref_count = 0;
+ tiles[k].dirty = FALSE;
+ tiles[k].shadow = shadow;
+ tiles[k].data = NULL;
+ tiles[k].drawable = drawable;
+
+ if (j == (drawable->ntile_cols - 1))
+ tiles[k].ewidth = right_tile;
+ else
+ tiles[k].ewidth = TILE_WIDTH;
+
+ if (i == (drawable->ntile_rows - 1))
+ tiles[k].eheight = bottom_tile;
+ else
+ tiles[k].eheight = TILE_HEIGHT;
+ }
+ }
+
+ if (shadow)
+ drawable->shadow_tiles = tiles;
+ else
+ drawable->tiles = tiles;
+ }
+
+ tile_num = row * drawable->ntile_cols + col;
+
+ return &tiles[tile_num];
+}
+
+GimpTile *
+gimp_drawable_get_tile2 (GimpDrawable *drawable,
+ gboolean shadow,
+ gint x,
+ gint y)
+{
+ gint row;
+ gint col;
+
+ g_return_val_if_fail (drawable != NULL, NULL);
+
+ col = x / TILE_WIDTH;
+ row = y / TILE_HEIGHT;
+
+ return gimp_drawable_get_tile (drawable, shadow, row, col);
+}
+
+void
+gimp_drawable_get_color_uchar (gint32 drawable_ID,
+ const GimpRGB *color,
+ guchar *color_uchar)
+{
+ g_return_if_fail (color != NULL);
+ g_return_if_fail (color_uchar != NULL);
+
+ switch (gimp_drawable_type (drawable_ID))
+ {
+ case GIMP_RGB_IMAGE:
+ gimp_rgb_get_uchar (color,
+ &color_uchar[0], &color_uchar[1], &color_uchar[2]);
+ color_uchar[3] = 255;
+ break;
+
+ case GIMP_RGBA_IMAGE:
+ gimp_rgba_get_uchar (color,
+ &color_uchar[0], &color_uchar[1], &color_uchar[2],
+ &color_uchar[3]);
+ break;
+
+ case GIMP_GRAY_IMAGE:
+ color_uchar[0] = gimp_rgb_luminance_uchar (color);
+ color_uchar[1] = 255;
+ break;
+
+ case GIMP_GRAYA_IMAGE:
+ color_uchar[0] = gimp_rgb_luminance_uchar (color);
+ gimp_rgba_get_uchar (color, NULL, NULL, NULL, &color_uchar[1]);
+ break;
+
+ default:
+ break;
+ }
+}
+
+guchar *
+gimp_drawable_get_thumbnail_data (gint32 drawable_ID,
+ gint *width,
+ gint *height,
+ gint *bpp)
+{
+ gint ret_width;
+ gint ret_height;
+ guchar *image_data;
+ gint data_size;
+
+ _gimp_drawable_thumbnail (drawable_ID,
+ *width,
+ *height,
+ &ret_width,
+ &ret_height,
+ bpp,
+ &data_size,
+ &image_data);
+
+ *width = ret_width;
+ *height = ret_height;
+
+ return image_data;
+}
+
+guchar *
+gimp_drawable_get_sub_thumbnail_data (gint32 drawable_ID,
+ gint src_x,
+ gint src_y,
+ gint src_width,
+ gint src_height,
+ gint *dest_width,
+ gint *dest_height,
+ gint *bpp)
+{
+ gint ret_width;
+ gint ret_height;
+ guchar *image_data;
+ gint data_size;
+
+ _gimp_drawable_sub_thumbnail (drawable_ID,
+ src_x, src_y,
+ src_width, src_height,
+ *dest_width,
+ *dest_height,
+ &ret_width,
+ &ret_height,
+ bpp,
+ &data_size,
+ &image_data);
+
+ *dest_width = ret_width;
+ *dest_height = ret_height;
+
+ return image_data;
+}
+
+/**
+ * gimp_drawable_is_valid:
+ * @drawable_ID: The drawable to check.
+ *
+ * Deprecated: Use gimp_item_is_valid() instead.
+ *
+ * Returns: Whether the drawable ID is valid.
+ *
+ * Since: 2.4
+ */
+gboolean
+gimp_drawable_is_valid (gint32 drawable_ID)
+{
+ return gimp_item_is_valid (drawable_ID);
+}
+
+/**
+ * gimp_drawable_is_layer:
+ * @drawable_ID: The drawable.
+ *
+ * Deprecated: Use gimp_item_is_layer() instead.
+ *
+ * Returns: TRUE if the drawable is a layer, FALSE otherwise.
+ */
+gboolean
+gimp_drawable_is_layer (gint32 drawable_ID)
+{
+ return gimp_item_is_layer (drawable_ID);
+}
+
+/**
+ * gimp_drawable_is_text_layer:
+ * @drawable_ID: The drawable.
+ *
+ * Deprecated: Use gimp_item_is_text_layer() instead.
+ *
+ * Returns: TRUE if the drawable is a text layer, FALSE otherwise.
+ *
+ * Since: 2.6
+ */
+gboolean
+gimp_drawable_is_text_layer (gint32 drawable_ID)
+{
+ return gimp_item_is_text_layer (drawable_ID);
+}
+
+/**
+ * gimp_drawable_is_layer_mask:
+ * @drawable_ID: The drawable.
+ *
+ * Deprecated: Use gimp_item_is_layer_mask() instead.
+ *
+ * Returns: TRUE if the drawable is a layer mask, FALSE otherwise.
+ */
+gboolean
+gimp_drawable_is_layer_mask (gint32 drawable_ID)
+{
+ return gimp_item_is_layer_mask (drawable_ID);
+}
+
+/**
+ * gimp_drawable_is_channel:
+ * @drawable_ID: The drawable.
+ *
+ * Deprecated: Use gimp_item_is_channel() instead.
+ *
+ * Returns: TRUE if the drawable is a channel, FALSE otherwise.
+ */
+gboolean
+gimp_drawable_is_channel (gint32 drawable_ID)
+{
+ return gimp_item_is_channel (drawable_ID);
+}
+
+/**
+ * gimp_drawable_delete:
+ * @drawable_ID: The drawable to delete.
+ *
+ * Deprecated: Use gimp_item_delete() instead.
+ *
+ * Returns: TRUE on success.
+ */
+gboolean
+gimp_drawable_delete (gint32 drawable_ID)
+{
+ return gimp_item_delete (drawable_ID);
+}
+
+/**
+ * gimp_drawable_get_image:
+ * @drawable_ID: The drawable.
+ *
+ * Deprecated: Use gimp_item_get_image() instead.
+ *
+ * Returns: The drawable's image.
+ */
+gint32
+gimp_drawable_get_image (gint32 drawable_ID)
+{
+ return gimp_item_get_image (drawable_ID);
+}
+
+/**
+ * gimp_drawable_get_name:
+ * @drawable_ID: The drawable.
+ *
+ * Deprecated: Use gimp_item_get_name() instead.
+ *
+ * Returns: The drawable name.
+ */
+gchar *
+gimp_drawable_get_name (gint32 drawable_ID)
+{
+ return gimp_item_get_name (drawable_ID);
+}
+
+/**
+ * gimp_drawable_set_name:
+ * @drawable_ID: The drawable.
+ * @name: The new drawable name.
+ *
+ * Deprecated: Use gimp_item_set_name() instead.
+ *
+ * Returns: TRUE on success.
+ */
+gboolean
+gimp_drawable_set_name (gint32 drawable_ID,
+ const gchar *name)
+{
+ return gimp_item_set_name (drawable_ID, name);
+}
+
+/**
+ * gimp_drawable_get_visible:
+ * @drawable_ID: The drawable.
+ *
+ * Deprecated: Use gimp_item_get_visible() instead.
+ *
+ * Returns: The drawable visibility.
+ */
+gboolean
+gimp_drawable_get_visible (gint32 drawable_ID)
+{
+ return gimp_item_get_visible (drawable_ID);
+}
+
+/**
+ * gimp_drawable_set_visible:
+ * @drawable_ID: The drawable.
+ * @visible: The new drawable visibility.
+ *
+ * Deprecated: Use gimp_item_set_visible() instead.
+ *
+ * Returns: TRUE on success.
+ */
+gboolean
+gimp_drawable_set_visible (gint32 drawable_ID,
+ gboolean visible)
+{
+ return gimp_item_set_visible (drawable_ID, visible);
+}
+
+/**
+ * gimp_drawable_get_linked:
+ * @drawable_ID: The drawable.
+ *
+ * Deprecated: Use gimp_item_get_linked() instead.
+ *
+ * Returns: The drawable linked state (for moves).
+ */
+gboolean
+gimp_drawable_get_linked (gint32 drawable_ID)
+{
+ return gimp_item_get_linked (drawable_ID);
+}
+
+/**
+ * gimp_drawable_set_linked:
+ * @drawable_ID: The drawable.
+ * @linked: The new drawable linked state.
+ *
+ * Deprecated: Use gimp_item_set_linked() instead.
+ *
+ * Returns: TRUE on success.
+ */
+gboolean
+gimp_drawable_set_linked (gint32 drawable_ID,
+ gboolean linked)
+{
+ return gimp_item_set_linked (drawable_ID, linked);
+}
+
+/**
+ * gimp_drawable_get_tattoo:
+ * @drawable_ID: The drawable.
+ *
+ * Deprecated: Use gimp_item_get_tattoo() instead.
+ *
+ * Returns: The drawable tattoo.
+ */
+gint
+gimp_drawable_get_tattoo (gint32 drawable_ID)
+{
+ return gimp_item_get_tattoo (drawable_ID);
+}
+
+/**
+ * gimp_drawable_set_tattoo:
+ * @drawable_ID: The drawable.
+ * @tattoo: The new drawable tattoo.
+ *
+ * Deprecated: Use gimp_item_set_tattoo() instead.
+ *
+ * Returns: TRUE on success.
+ */
+gboolean
+gimp_drawable_set_tattoo (gint32 drawable_ID,
+ gint tattoo)
+{
+ return gimp_item_set_tattoo (drawable_ID, tattoo);
+}
+
+/**
+ * gimp_drawable_parasite_find:
+ * @drawable_ID: The drawable.
+ * @name: The name of the parasite to find.
+ *
+ * Deprecated: Use gimp_item_get_parasite() instead.
+ *
+ * Returns: The found parasite.
+ **/
+GimpParasite *
+gimp_drawable_parasite_find (gint32 drawable_ID,
+ const gchar *name)
+{
+ return gimp_item_get_parasite (drawable_ID, name);
+}
+
+/**
+ * gimp_drawable_parasite_attach:
+ * @drawable_ID: The drawable.
+ * @parasite: The parasite to attach to a drawable.
+ *
+ * Deprecated: Use gimp_item_attach_parasite() instead.
+ *
+ * Returns: TRUE on success.
+ **/
+gboolean
+gimp_drawable_parasite_attach (gint32 drawable_ID,
+ const GimpParasite *parasite)
+{
+ return gimp_item_attach_parasite (drawable_ID, parasite);
+}
+
+/**
+ * gimp_drawable_parasite_detach:
+ * @drawable_ID: The drawable.
+ * @name: The name of the parasite to detach from a drawable.
+ *
+ * Deprecated: Use gimp_item_detach_parasite() instead.
+ *
+ * Returns: TRUE on success.
+ **/
+gboolean
+gimp_drawable_parasite_detach (gint32 drawable_ID,
+ const gchar *name)
+{
+ return gimp_item_detach_parasite (drawable_ID, name);
+}
+
+/**
+ * gimp_drawable_parasite_list:
+ * @drawable_ID: The drawable.
+ * @num_parasites: The number of attached parasites.
+ * @parasites: The names of currently attached parasites.
+ *
+ * Deprecated: Use gimp_item_get_parasite_list() instead.
+ *
+ * Returns: TRUE on success.
+ **/
+gboolean
+gimp_drawable_parasite_list (gint32 drawable_ID,
+ gint *num_parasites,
+ gchar ***parasites)
+{
+ *parasites = gimp_item_get_parasite_list (drawable_ID, num_parasites);
+
+ return *parasites != NULL;
+}
+
+/**
+ * gimp_drawable_attach_new_parasite:
+ * @drawable_ID: the ID of the #GimpDrawable to attach the #GimpParasite to.
+ * @name: the name of the #GimpParasite to create and attach.
+ * @flags: the flags set on the #GimpParasite.
+ * @size: the size of the parasite data in bytes.
+ * @data: a pointer to the data attached with the #GimpParasite.
+ *
+ * Convenience function that creates a parasite and attaches it
+ * to GIMP.
+ *
+ * Deprecated: use gimp_item_attach_parasite() instead.
+ *
+ * Return value: TRUE on successful creation and attachment of
+ * the new parasite.
+ *
+ * See Also: gimp_drawable_parasite_attach()
+ */
+gboolean
+gimp_drawable_attach_new_parasite (gint32 drawable_ID,
+ const gchar *name,
+ gint flags,
+ gint size,
+ gconstpointer data)
+{
+ GimpParasite *parasite = gimp_parasite_new (name, flags, size, data);
+ gboolean success;
+
+ success = gimp_item_attach_parasite (drawable_ID, parasite);
+
+ gimp_parasite_free (parasite);
+
+ return success;
+}
+
+/**
+ * gimp_drawable_get_buffer:
+ * @drawable_ID: the ID of the #GimpDrawable to get the buffer for.
+ *
+ * Returns a #GeglBuffer of a specified drawable. The buffer can be used
+ * like any other GEGL buffer. Its data will we synced back with the core
+ * drawable when the buffer gets destroyed, or when gegl_buffer_flush()
+ * is called.
+ *
+ * Return value: The #GeglBuffer.
+ *
+ * See Also: gimp_drawable_get_shadow_buffer()
+ *
+ * Since: 2.10
+ */
+GeglBuffer *
+gimp_drawable_get_buffer (gint32 drawable_ID)
+{
+ gimp_plugin_enable_precision ();
+
+ if (gimp_item_is_valid (drawable_ID))
+ {
+ GimpDrawable *drawable;
+
+ drawable = gimp_drawable_get (drawable_ID);
+
+ if (drawable)
+ {
+ GeglTileBackend *backend;
+ GeglBuffer *buffer;
+
+ backend = _gimp_tile_backend_plugin_new (drawable, FALSE);
+ buffer = gegl_buffer_new_for_backend (NULL, backend);
+ g_object_unref (backend);
+
+ return buffer;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * gimp_drawable_get_shadow_buffer:
+ * @drawable_ID: the ID of the #GimpDrawable to get the buffer for.
+ *
+ * Returns a #GeglBuffer of a specified drawable's shadow tiles. The
+ * buffer can be used like any other GEGL buffer. Its data will we
+ * synced back with the core drawable's shadow tiles when the buffer
+ * gets destroyed, or when gegl_buffer_flush() is called.
+ *
+ * Return value: The #GeglBuffer.
+ *
+ * See Also: gimp_drawable_get_shadow_buffer()
+ *
+ * Since: 2.10
+ */
+GeglBuffer *
+gimp_drawable_get_shadow_buffer (gint32 drawable_ID)
+{
+ GimpDrawable *drawable;
+
+ gimp_plugin_enable_precision ();
+
+ drawable = gimp_drawable_get (drawable_ID);
+
+ if (drawable)
+ {
+ GeglTileBackend *backend;
+ GeglBuffer *buffer;
+
+ backend = _gimp_tile_backend_plugin_new (drawable, TRUE);
+ buffer = gegl_buffer_new_for_backend (NULL, backend);
+ g_object_unref (backend);
+
+ return buffer;
+ }
+
+ return NULL;
+}
+
+/**
+ * gimp_drawable_get_format:
+ * @drawable_ID: the ID of the #GimpDrawable to get the format for.
+ *
+ * Returns the #Babl format of the drawable.
+ *
+ * Return value: The #Babl format.
+ *
+ * Since: 2.10
+ */
+const Babl *
+gimp_drawable_get_format (gint32 drawable_ID)
+{
+ static GHashTable *palette_formats = NULL;
+ const Babl *format = NULL;
+ gchar *format_str = _gimp_drawable_get_format (drawable_ID);
+
+ if (format_str)
+ {
+ if (gimp_drawable_is_indexed (drawable_ID))
+ {
+ gint32 image_ID = gimp_item_get_image (drawable_ID);
+ guchar *colormap;
+ gint n_colors;
+
+ colormap = gimp_image_get_colormap (image_ID, &n_colors);
+
+ if (!palette_formats)
+ palette_formats = g_hash_table_new (g_str_hash, g_str_equal);
+
+ format = g_hash_table_lookup (palette_formats, format_str);
+
+ if (!format)
+ {
+ const Babl *palette;
+ const Babl *palette_alpha;
+
+ babl_new_palette (format_str, &palette, &palette_alpha);
+ g_hash_table_insert (palette_formats,
+ (gpointer) babl_get_name (palette),
+ (gpointer) palette);
+ g_hash_table_insert (palette_formats,
+ (gpointer) babl_get_name (palette_alpha),
+ (gpointer) palette_alpha);
+
+ if (gimp_drawable_has_alpha (drawable_ID))
+ format = palette_alpha;
+ else
+ format = palette;
+ }
+
+ if (colormap)
+ {
+ babl_palette_set_palette (format,
+ babl_format ("R'G'B' u8"),
+ colormap, n_colors);
+ g_free (colormap);
+ }
+ }
+ else
+ {
+ format = babl_format (format_str);
+ }
+
+ g_free (format_str);
+ }
+
+ return format;
+}
+/**
+ * gimp_drawable_get_thumbnail_format:
+ * @drawable_ID: the ID of the #GimpDrawable to get the thumbnail format for.
+ *
+ * Returns the #Babl thumbnail format of the drawable.
+ *
+ * Return value: The #Babl thumbnail format.
+ *
+ * Since: 2.10.14
+ */
+const Babl *
+gimp_drawable_get_thumbnail_format (gint32 drawable_ID)
+{
+ const Babl *format = NULL;
+ gchar *format_str = _gimp_drawable_get_thumbnail_format (drawable_ID);
+
+ if (format_str)
+ format = babl_format (format_str);
+
+ return format;
+}