gimp/libgimp/gimplayer.c

311 lines
8.9 KiB
C
Raw Normal View History

/* LIBGIMP - The GIMP Library
* Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
*
* gimplayer.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
* Lesser 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"
#include <string.h>
#include "gimp.h"
static GimpLayer * gimp_layer_real_copy (GimpLayer *layer);
libgimp: use G_DECLARE_DERIVABLE_TYPE and G_DECLARE_FINAL_TYPE for… … the public API. This was initially proposed by Niels De Graef in !101, and though I still think this is much less practical for day-to-day development, it is actually much nicer for the public part of the API. So let's use these only in public libgimp* API only, not in core. I actually already started to use these for some of the libgimpwidgets classes and am now moving libgimp main classes to these macros. * It doesn't expose the priv member (which is completely useless for plug-in developers, only to be used for core development). * It forces us to never have any variable members in the public API (which we were doing fine so far in newest API, but it's nice to be enforced with these macros). * When using G_DECLARE_FINAL_TYPE in particular, it adds flexibility as we can change the structure size and the members order as these are not exposed. And if some day, we make the class derivable with some signals to handle, only then will we expose the class with some _gimp_reserved* padding (instead of from the start when none is needed). Therefore we will allow for further extension far in the future. Moreover most of these libgimp classes were so far not using any private values, so we were declaring a `priv` member with a bogus contents just "in case we needed it in future" (as we couldn't change the struct size). So even the easiness of having a priv member was very relative for this public API so far (unlike in core code where we actually have much more complex interactions and using priv data all the time).
2021-04-06 18:39:52 +08:00
G_DEFINE_TYPE (GimpLayer, gimp_layer, GIMP_TYPE_DRAWABLE)
#define parent_class gimp_layer_parent_class
static void
gimp_layer_class_init (GimpLayerClass *klass)
{
klass->copy = gimp_layer_real_copy;
}
static void
gimp_layer_init (GimpLayer *layer)
{
}
/* Public API. */
/**
* gimp_layer_get_by_id:
* @layer_id: The layer id.
*
* Returns a #GimpLayer representing @layer_id. This function calls
* gimp_item_get_by_id() and returns the item if it is layer or %NULL
* otherwise.
*
* Returns: (nullable) (transfer none): a #GimpLayer for @layer_id or
* %NULL if @layer_id does not represent a valid layer. The
* object belongs to libgimp and you must not modify or unref
* it.
*
* Since: 3.0
**/
GimpLayer *
gimp_layer_get_by_id (gint32 layer_id)
{
GimpItem *item = gimp_item_get_by_id (layer_id);
if (GIMP_IS_LAYER (item))
return (GimpLayer *) item;
return NULL;
}
/**
* gimp_layer_new:
* @image: The image to which to add the layer.
* @name: The layer name.
* @width: The layer width.
* @height: The layer height.
* @type: The layer type.
* @opacity: The layer opacity.
* @mode: The layer combination mode.
*
* Create a new layer.
*
* This procedure creates a new layer with the specified width, height,
* and type. Name, opacity, and mode are also supplied parameters. The
* new layer still needs to be added to the image, as this is not
* automatic. Add the new layer with the gimp_image_insert_layer()
* command. Other attributes such as layer mask modes, and offsets
* should be set with explicit procedure calls.
*
* Returns: (transfer none): The newly created layer.
* The object belongs to libgimp and you should not free it.
*
* Since: 3.0
*/
GimpLayer *
gimp_layer_new (GimpImage *image,
const gchar *name,
gint width,
gint height,
GimpImageType type,
gdouble opacity,
GimpLayerMode mode)
{
return _gimp_layer_new (image,
width,
height,
type,
name,
opacity,
mode);
}
/**
* gimp_layer_copy:
* @layer: The layer to copy.
*
* Copy a layer.
*
* This procedure copies the specified layer and returns the copy. The
* newly copied layer is for use within the original layer's image. It
* should not be subsequently added to any other image.
*
* Returns: (transfer none): The newly copied layer.
* The object belongs to libgimp and you should not free it.
*
* Since: 3.0
*/
GimpLayer *
gimp_layer_copy (GimpLayer *layer)
{
return GIMP_LAYER_GET_CLASS (layer)->copy (layer);
}
app/actions/layers-actions.c app/actions/layers-commands.[ch] 2005-07-10 Michael Natterer <mitch@gimp.org> * app/actions/layers-actions.c * app/actions/layers-commands.[ch] * app/core/core-enums.[ch] * app/core/gimpimage-undo-push.[ch] * app/core/gimplayer-floating-sel.c * app/core/gimplayer.[ch] * app/text/gimptextlayer-xcf.c * app/widgets/gimphelp-ids.h * app/widgets/gimplayertreeview.[ch] * app/xcf/xcf-load.c * app/xcf/xcf-private.h * app/xcf/xcf-save.c * tools/pdbgen/pdb/layer.pdb * menus/image-menu.xml.in * libgimp/gimp.def: did a global s/preserve_trans/lock_alpha/ in preparation for more layer locking flags. * app/pdb/procedural_db.c * libgimp/gimplayer.[ch]: added compat stuff for preserve_trans. * app/pdb/layer_cmds.c * libgimp/gimplayer_pdb.[ch]: regenerated. * plug-ins/common/colortoalpha.c * plug-ins/common/iwarp.c * plug-ins/common/psd.c * plug-ins/common/psd_save.c * plug-ins/common/psp.c * plug-ins/common/rotate.c * plug-ins/common/threshold_alpha.c * plug-ins/common/vpropagate.c * plug-ins/script-fu/scripts/3d-outline.scm * plug-ins/script-fu/scripts/alien-glow-bar.scm * plug-ins/script-fu/scripts/alien-glow-bullet.scm * plug-ins/script-fu/scripts/alien-glow-logo.scm * plug-ins/script-fu/scripts/basic1-logo.scm * plug-ins/script-fu/scripts/basic2-logo.scm * plug-ins/script-fu/scripts/beveled-pattern-button.scm * plug-ins/script-fu/scripts/blend-anim.scm * plug-ins/script-fu/scripts/blended-logo.scm * plug-ins/script-fu/scripts/bovinated-logo.scm * plug-ins/script-fu/scripts/burn-in-anim.scm * plug-ins/script-fu/scripts/carved-logo.scm * plug-ins/script-fu/scripts/chalk.scm * plug-ins/script-fu/scripts/chip-away.scm * plug-ins/script-fu/scripts/comic-logo.scm * plug-ins/script-fu/scripts/coolmetal-logo.scm * plug-ins/script-fu/scripts/crystal-logo.scm * plug-ins/script-fu/scripts/drop-shadow.scm * plug-ins/script-fu/scripts/gimp-headers.scm * plug-ins/script-fu/scripts/gimp-labels.scm * plug-ins/script-fu/scripts/glowing-logo.scm * plug-ins/script-fu/scripts/gradient-bevel-logo.scm * plug-ins/script-fu/scripts/image-structure.scm * plug-ins/script-fu/scripts/neon-logo.scm * plug-ins/script-fu/scripts/perspective-shadow.scm * plug-ins/script-fu/scripts/starburst-logo.scm * plug-ins/script-fu/scripts/starscape-logo.scm * plug-ins/script-fu/scripts/textured-logo.scm * plug-ins/script-fu/scripts/title-header.scm * plug-ins/script-fu/scripts/waves-anim.scm * plug-ins/xjt/xjt.c: changed accordingly.
2005-07-11 05:17:22 +08:00
/**
* gimp_layer_new_from_pixbuf:
* @image: The RGB image to which to add the layer.
* @name: The layer name.
* @pixbuf: A GdkPixbuf.
* @opacity: The layer opacity.
* @mode: The layer combination mode.
* @progress_start: start of progress
* @progress_end: end of progress
*
* Create a new layer from a %GdkPixbuf.
*
* This procedure creates a new layer from the given %GdkPixbuf. The
* image has to be an RGB image and just like with gimp_layer_new()
* you will still need to add the layer to it.
*
* If you pass @progress_end > @progress_start to this function,
* gimp_progress_update() will be called for. You have to call
* gimp_progress_init() beforehand then.
*
* Returns: (transfer none): The newly created layer.
* The object belongs to libgimp and you should not free it.
*
* Since: 2.2
*/
GimpLayer *
gimp_layer_new_from_pixbuf (GimpImage *image,
const gchar *name,
GdkPixbuf *pixbuf,
gdouble opacity,
GimpLayerMode mode,
gdouble progress_start,
gdouble progress_end)
{
GeglBuffer *dest_buffer;
GimpLayer *layer;
gint width;
gint height;
gint bpp;
gdouble range = progress_end - progress_start;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
if (gimp_image_get_base_type (image) != GIMP_RGB)
{
g_warning ("gimp_layer_new_from_pixbuf() needs an RGB image");
return NULL;
}
if (gdk_pixbuf_get_colorspace (pixbuf) != GDK_COLORSPACE_RGB)
{
g_warning ("gimp_layer_new_from_pixbuf() assumes that GdkPixbuf is RGB");
return NULL;
}
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
bpp = gdk_pixbuf_get_n_channels (pixbuf);
layer = gimp_layer_new (image, name, width, height,
bpp == 3 ? GIMP_RGB_IMAGE : GIMP_RGBA_IMAGE,
opacity, mode);
if (! layer)
return NULL;
dest_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
gegl_buffer_set (dest_buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
gimp_pixbuf_get_format (pixbuf),
gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_rowstride (pixbuf));
g_object_unref (dest_buffer);
if (range > 0.0)
gimp_progress_update (progress_end);
return layer;
}
/**
* gimp_layer_new_from_surface:
* @image: The RGB image to which to add the layer.
* @name: The layer name.
* @surface: A Cairo image surface.
* @progress_start: start of progress
* @progress_end: end of progress
*
* Create a new layer from a #cairo_surface_t.
*
* This procedure creates a new layer from the given
* #cairo_surface_t. The image has to be an RGB image and just like
* with gimp_layer_new() you will still need to add the layer to it.
*
* If you pass @progress_end > @progress_start to this function,
* gimp_progress_update() will be called for. You have to call
* gimp_progress_init() beforehand then.
*
* Returns: (transfer none): The newly created layer.
* The object belongs to libgimp and you should not free it.
*
* Since: 2.8
*/
GimpLayer *
gimp_layer_new_from_surface (GimpImage *image,
const gchar *name,
cairo_surface_t *surface,
gdouble progress_start,
gdouble progress_end)
{
GeglBuffer *src_buffer;
GeglBuffer *dest_buffer;
GimpLayer *layer;
gint width;
gint height;
cairo_format_t format;
gdouble range = progress_end - progress_start;
g_return_val_if_fail (surface != NULL, NULL);
g_return_val_if_fail (cairo_surface_get_type (surface) ==
CAIRO_SURFACE_TYPE_IMAGE, NULL);
if (gimp_image_get_base_type (image) != GIMP_RGB)
{
g_warning ("gimp_layer_new_from_surface() needs an RGB image");
return NULL;
}
width = cairo_image_surface_get_width (surface);
height = cairo_image_surface_get_height (surface);
format = cairo_image_surface_get_format (surface);
if (format != CAIRO_FORMAT_ARGB32 &&
format != CAIRO_FORMAT_RGB24)
{
g_warning ("gimp_layer_new_from_surface() assumes that surface is RGB");
return NULL;
}
layer = gimp_layer_new (image, name, width, height,
format == CAIRO_FORMAT_RGB24 ?
GIMP_RGB_IMAGE : GIMP_RGBA_IMAGE,
100.0,
gimp_image_get_default_new_layer_mode (image));
if (layer == NULL)
return NULL;
src_buffer = gimp_cairo_surface_create_buffer (surface);
dest_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
gegl_buffer_copy (src_buffer, NULL, GEGL_ABYSS_NONE,
dest_buffer, NULL);
g_object_unref (src_buffer);
g_object_unref (dest_buffer);
if (range > 0.0)
gimp_progress_update (progress_end);
return layer;
}
/* private functions */
static GimpLayer *
gimp_layer_real_copy (GimpLayer *layer)
{
return _gimp_layer_copy (layer, FALSE);
}