2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
1998-06-30 23:31:32 +08:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
1998-06-30 23:31:32 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
1998-06-30 23:31:32 +08:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
1998-06-30 23:31:32 +08:00
|
|
|
*/
|
2000-12-17 05:37:03 +08:00
|
|
|
|
2000-05-27 06:28:40 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
2011-04-28 21:50:39 +08:00
|
|
|
#include <cairo.h>
|
2008-10-10 04:24:04 +08:00
|
|
|
#include <gegl.h>
|
2012-05-03 09:36:22 +08:00
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
2000-12-17 05:37:03 +08:00
|
|
|
|
2006-08-29 22:46:32 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2001-01-24 07:56:18 +08:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2001-01-24 07:56:18 +08:00
|
|
|
|
2001-05-10 06:34:59 +08:00
|
|
|
#include "core-types.h"
|
2000-12-29 23:22:01 +08:00
|
|
|
|
2012-04-22 05:55:40 +08:00
|
|
|
#include "gegl/gimp-babl.h"
|
2012-10-22 22:14:56 +08:00
|
|
|
#include "gegl/gimp-gegl-apply-operation.h"
|
2018-05-19 02:57:19 +08:00
|
|
|
#include "gegl/gimp-gegl-loops.h"
|
2019-07-31 01:25:54 +08:00
|
|
|
#include "gegl/gimp-gegl-utils.h"
|
2010-06-07 01:54:44 +08:00
|
|
|
|
2014-08-12 19:57:57 +08:00
|
|
|
#include "gimp-memsize.h"
|
2012-03-30 19:03:51 +08:00
|
|
|
#include "gimp-utils.h"
|
2001-02-02 02:44:22 +08:00
|
|
|
#include "gimpchannel.h"
|
2001-07-08 06:49:01 +08:00
|
|
|
#include "gimpcontext.h"
|
2003-10-06 22:40:12 +08:00
|
|
|
#include "gimpdrawable-combine.h"
|
2016-10-10 06:02:16 +08:00
|
|
|
#include "gimpdrawable-fill.h"
|
2016-05-19 23:38:55 +08:00
|
|
|
#include "gimpdrawable-floating-selection.h"
|
2001-02-07 08:06:58 +08:00
|
|
|
#include "gimpdrawable-preview.h"
|
2009-02-04 07:57:11 +08:00
|
|
|
#include "gimpdrawable-private.h"
|
2008-04-22 01:20:51 +08:00
|
|
|
#include "gimpdrawable-shadow.h"
|
2003-05-13 21:57:11 +08:00
|
|
|
#include "gimpdrawable-transform.h"
|
2013-04-12 01:06:23 +08:00
|
|
|
#include "gimpfilterstack.h"
|
2000-12-30 08:16:50 +08:00
|
|
|
#include "gimpimage.h"
|
2006-04-07 17:21:18 +08:00
|
|
|
#include "gimpimage-colormap.h"
|
2003-02-14 22:14:29 +08:00
|
|
|
#include "gimpimage-undo-push.h"
|
2001-11-23 07:46:13 +08:00
|
|
|
#include "gimpmarshal.h"
|
2004-07-14 07:04:05 +08:00
|
|
|
#include "gimppickable.h"
|
2004-08-11 02:47:21 +08:00
|
|
|
#include "gimpprogress.h"
|
2001-05-25 01:09:57 +08:00
|
|
|
|
2010-01-03 06:41:52 +08:00
|
|
|
#include "gimp-log.h"
|
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
1998-06-30 23:31:32 +08:00
|
|
|
|
2000-05-27 06:28:40 +08:00
|
|
|
|
2019-07-31 01:27:11 +08:00
|
|
|
#define PAINT_UPDATE_CHUNK_WIDTH 32
|
|
|
|
#define PAINT_UPDATE_CHUNK_HEIGHT 32
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
|
|
|
|
|
2000-05-27 06:28:40 +08:00
|
|
|
enum
|
|
|
|
{
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
UPDATE,
|
2018-12-28 15:06:40 +08:00
|
|
|
FORMAT_CHANGED,
|
2003-05-21 19:34:00 +08:00
|
|
|
ALPHA_CHANGED,
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
BOUNDING_BOX_CHANGED,
|
1998-06-30 23:31:32 +08:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2012-11-12 17:55:41 +08:00
|
|
|
enum
|
|
|
|
{
|
2013-09-05 16:37:09 +08:00
|
|
|
PROP_0,
|
|
|
|
PROP_BUFFER
|
2012-11-12 17:55:41 +08:00
|
|
|
};
|
|
|
|
|
2001-01-20 21:21:49 +08:00
|
|
|
|
2001-07-11 20:39:49 +08:00
|
|
|
/* local function prototypes */
|
|
|
|
|
2016-05-01 05:41:32 +08:00
|
|
|
static void gimp_color_managed_iface_init (GimpColorManagedInterface *iface);
|
|
|
|
static void gimp_pickable_iface_init (GimpPickableInterface *iface);
|
2001-08-11 22:39:19 +08:00
|
|
|
|
2011-09-24 01:55:24 +08:00
|
|
|
static void gimp_drawable_dispose (GObject *object);
|
2003-02-11 21:52:47 +08:00
|
|
|
static void gimp_drawable_finalize (GObject *object);
|
2012-11-12 17:55:41 +08:00
|
|
|
static void gimp_drawable_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_drawable_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
2001-08-11 22:39:19 +08:00
|
|
|
|
2003-11-17 01:51:36 +08:00
|
|
|
static gint64 gimp_drawable_get_memsize (GimpObject *object,
|
|
|
|
gint64 *gui_size);
|
2002-01-31 00:14:26 +08:00
|
|
|
|
2005-05-25 18:05:17 +08:00
|
|
|
static gboolean gimp_drawable_get_size (GimpViewable *viewable,
|
|
|
|
gint *width,
|
|
|
|
gint *height);
|
app: when freezing a drawable's preview, freeze ancestors' previews
Add GimpViewable::preview_{freeze,thaw}() virtual functions, which
get called when the viewable's preview is frozen/thawed. Implement
the functions in GimpDrawable, recursively freezing the parent
drawable's preview (or the image's preview, for top-level
drawables) while the drawable's preview is frozen. For layer
masks, freeze the associated layer's parent.
This avoids updating layer-group/image previews while painting on,
or applying a filter to, a descendant layer. This both reduces
lag, and fixes a discrepancy between the layer's preview, which
isn't updated, and its parents' previews.
2019-03-29 00:03:49 +08:00
|
|
|
static void gimp_drawable_preview_freeze (GimpViewable *viewable);
|
|
|
|
static void gimp_drawable_preview_thaw (GimpViewable *viewable);
|
2003-02-11 21:52:47 +08:00
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
static GeglNode * gimp_drawable_get_node (GimpFilter *filter);
|
|
|
|
|
2008-04-22 01:20:51 +08:00
|
|
|
static void gimp_drawable_removed (GimpItem *item);
|
2003-02-11 21:52:47 +08:00
|
|
|
static GimpItem * gimp_drawable_duplicate (GimpItem *item,
|
2008-01-08 19:46:15 +08:00
|
|
|
GType new_type);
|
2003-05-07 19:09:00 +08:00
|
|
|
static void gimp_drawable_scale (GimpItem *item,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint new_offset_x,
|
|
|
|
gint new_offset_y,
|
2004-02-09 08:09:20 +08:00
|
|
|
GimpInterpolationType interp_type,
|
2007-12-04 19:30:31 +08:00
|
|
|
GimpProgress *progress);
|
2003-05-07 21:01:17 +08:00
|
|
|
static void gimp_drawable_resize (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2016-10-10 06:02:16 +08:00
|
|
|
GimpFillType fill_type,
|
2003-05-07 21:01:17 +08:00
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y);
|
2003-05-13 21:57:11 +08:00
|
|
|
static void gimp_drawable_flip (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-05-13 21:57:11 +08:00
|
|
|
GimpOrientationType flip_type,
|
|
|
|
gdouble axis,
|
|
|
|
gboolean clip_result);
|
2003-05-20 18:36:29 +08:00
|
|
|
static void gimp_drawable_rotate (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-05-20 18:36:29 +08:00
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gboolean clip_result);
|
2003-05-13 21:57:11 +08:00
|
|
|
static void gimp_drawable_transform (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-07-07 21:50:48 +08:00
|
|
|
const GimpMatrix3 *matrix,
|
2007-12-04 19:30:31 +08:00
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
GimpTransformResize clip_result,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress);
|
1998-06-30 23:31:32 +08:00
|
|
|
|
2016-05-01 05:41:32 +08:00
|
|
|
static const guint8 *
|
|
|
|
gimp_drawable_get_icc_profile (GimpColorManaged *managed,
|
|
|
|
gsize *len);
|
|
|
|
static GimpColorProfile *
|
|
|
|
gimp_drawable_get_color_profile (GimpColorManaged *managed);
|
|
|
|
static void gimp_drawable_profile_changed (GimpColorManaged *managed);
|
|
|
|
|
2007-04-28 00:07:49 +08:00
|
|
|
static gboolean gimp_drawable_get_pixel_at (GimpPickable *pickable,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
2012-04-21 16:03:32 +08:00
|
|
|
const Babl *format,
|
|
|
|
gpointer pixel);
|
2018-05-19 02:57:19 +08:00
|
|
|
static void gimp_drawable_get_pixel_average (GimpPickable *pickable,
|
|
|
|
const GeglRectangle *rect,
|
|
|
|
const Babl *format,
|
|
|
|
gpointer pixel);
|
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
static void gimp_drawable_real_update (GimpDrawable *drawable,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
|
|
|
gint height);
|
|
|
|
|
2016-05-20 05:51:44 +08:00
|
|
|
static gint64 gimp_drawable_real_estimate_memsize (GimpDrawable *drawable,
|
2014-06-15 05:12:22 +08:00
|
|
|
GimpComponentType component_type,
|
2007-12-04 19:30:31 +08:00
|
|
|
gint width,
|
|
|
|
gint height);
|
|
|
|
|
app: add gimp_drawable_update_all()
Add a new GimpDrawable::update_all() virtual function, and a
corresponding gimp_drawable_update_all() function, which updates
the full contents of the drawable. Unlike calling
`gimp_drawable_update (drawable, 0, 0, -1, -1)`, which updates the
entire drawable area, gimp_drawable_update_all() only updates the
area that has actual content. While the default implentation does
simply update the entire drawable area, GimpGroupLayer overrides
this function to recursively update its child layers, rather than
the its entire area.
2019-06-10 15:42:07 +08:00
|
|
|
static void gimp_drawable_real_update_all (GimpDrawable *drawable);
|
|
|
|
|
2019-02-17 01:56:20 +08:00
|
|
|
static GimpComponentMask
|
|
|
|
gimp_drawable_real_get_active_mask (GimpDrawable *drawable);
|
|
|
|
|
2020-01-17 17:24:31 +08:00
|
|
|
static gboolean gimp_drawable_real_supports_alpha
|
|
|
|
(GimpDrawable *drawable);
|
|
|
|
|
2009-09-12 03:23:35 +08:00
|
|
|
static void gimp_drawable_real_convert_type (GimpDrawable *drawable,
|
|
|
|
GimpImage *dest_image,
|
2012-10-14 04:56:32 +08:00
|
|
|
const Babl *new_format,
|
2018-08-06 04:19:17 +08:00
|
|
|
GimpColorProfile *src_profile,
|
2016-04-29 06:42:42 +08:00
|
|
|
GimpColorProfile *dest_profile,
|
2016-11-08 03:41:39 +08:00
|
|
|
GeglDitherMethod layer_dither_type,
|
|
|
|
GeglDitherMethod mask_dither_type,
|
2015-10-22 04:22:30 +08:00
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress);
|
2009-09-12 03:23:35 +08:00
|
|
|
|
2012-03-22 07:07:48 +08:00
|
|
|
static GeglBuffer * gimp_drawable_real_get_buffer (GimpDrawable *drawable);
|
2012-03-22 06:37:16 +08:00
|
|
|
static void gimp_drawable_real_set_buffer (GimpDrawable *drawable,
|
2004-03-13 21:56:09 +08:00
|
|
|
gboolean push_undo,
|
|
|
|
const gchar *undo_desc,
|
2012-03-22 06:37:16 +08:00
|
|
|
GeglBuffer *buffer,
|
2019-08-02 02:41:47 +08:00
|
|
|
const GeglRectangle *bounds);
|
2004-03-13 21:56:09 +08:00
|
|
|
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
static GeglRectangle gimp_drawable_real_get_bounding_box
|
|
|
|
(GimpDrawable *drawable);
|
|
|
|
|
2004-04-01 22:51:58 +08:00
|
|
|
static void gimp_drawable_real_push_undo (GimpDrawable *drawable,
|
|
|
|
const gchar *undo_desc,
|
2012-03-22 21:13:17 +08:00
|
|
|
GeglBuffer *buffer,
|
2004-04-01 22:51:58 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
|
|
|
gint height);
|
2004-03-15 22:10:30 +08:00
|
|
|
static void gimp_drawable_real_swap_pixels (GimpDrawable *drawable,
|
2012-03-22 21:13:17 +08:00
|
|
|
GeglBuffer *buffer,
|
2004-03-15 22:10:30 +08:00
|
|
|
gint x,
|
2012-03-22 21:25:45 +08:00
|
|
|
gint y);
|
2017-04-22 03:21:10 +08:00
|
|
|
static GeglNode * gimp_drawable_real_get_source_node (GimpDrawable *drawable);
|
2004-03-15 22:10:30 +08:00
|
|
|
|
2018-12-28 15:06:40 +08:00
|
|
|
static void gimp_drawable_format_changed (GimpDrawable *drawable);
|
|
|
|
static void gimp_drawable_alpha_changed (GimpDrawable *drawable);
|
|
|
|
|
2001-01-10 08:36:54 +08:00
|
|
|
|
2005-12-11 03:24:36 +08:00
|
|
|
G_DEFINE_TYPE_WITH_CODE (GimpDrawable, gimp_drawable, GIMP_TYPE_ITEM,
|
app, libgimp*, modules: don't use g_type_class_add_private() ...
... and G_TYPE_INSTANCE_GET_PRIVATE()
g_type_class_add_private() and G_TYPE_INSTANCE_GET_PRIVATE() were
deprecated in GLib 2.58. Instead, use
G_DEFINE_[ABSTRACT_]TYPE_WITH_PRIVATE(), and
G_ADD_PRIVATE[_DYNAMIC](), and the implictly-defined
foo_get_instance_private() functions, all of which are available in
the GLib versions we depend on.
This commit only covers types registered using one of the
G_DEFINE_FOO() macros (i.e., most types), but not types with a
custom registration function, of which we still have a few -- GLib
currently only provides a (non-deprecated) public API for adding a
private struct using the G_DEFINE_FOO() macros.
Note that this commit was 99% auto-generated (because I'm not
*that* crazy :), so if there are any style mismatches... we'll have
to live with them for now.
2018-09-19 00:09:39 +08:00
|
|
|
G_ADD_PRIVATE (GimpDrawable)
|
2016-05-01 05:41:32 +08:00
|
|
|
G_IMPLEMENT_INTERFACE (GIMP_TYPE_COLOR_MANAGED,
|
|
|
|
gimp_color_managed_iface_init)
|
2005-12-11 03:24:36 +08:00
|
|
|
G_IMPLEMENT_INTERFACE (GIMP_TYPE_PICKABLE,
|
2016-05-01 05:41:32 +08:00
|
|
|
gimp_pickable_iface_init))
|
2001-01-20 21:21:49 +08:00
|
|
|
|
2005-12-11 03:24:36 +08:00
|
|
|
#define parent_class gimp_drawable_parent_class
|
2000-12-29 00:19:55 +08:00
|
|
|
|
2005-12-11 03:24:36 +08:00
|
|
|
static guint gimp_drawable_signals[LAST_SIGNAL] = { 0 };
|
2000-12-29 00:19:55 +08:00
|
|
|
|
1998-06-30 23:31:32 +08:00
|
|
|
|
|
|
|
static void
|
2000-12-29 00:19:55 +08:00
|
|
|
gimp_drawable_class_init (GimpDrawableClass *klass)
|
1998-06-30 23:31:32 +08:00
|
|
|
{
|
2004-07-14 18:31:59 +08:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
|
|
|
GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
|
2013-04-11 08:54:42 +08:00
|
|
|
GimpFilterClass *filter_class = GIMP_FILTER_CLASS (klass);
|
2004-07-14 18:31:59 +08:00
|
|
|
GimpItemClass *item_class = GIMP_ITEM_CLASS (klass);
|
2001-01-10 08:36:54 +08:00
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
gimp_drawable_signals[UPDATE] =
|
|
|
|
g_signal_new ("update",
|
2004-07-14 18:31:59 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpDrawableClass, update),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__INT_INT_INT_INT,
|
|
|
|
G_TYPE_NONE, 4,
|
|
|
|
G_TYPE_INT,
|
|
|
|
G_TYPE_INT,
|
|
|
|
G_TYPE_INT,
|
|
|
|
G_TYPE_INT);
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
|
2018-12-28 15:06:40 +08:00
|
|
|
gimp_drawable_signals[FORMAT_CHANGED] =
|
|
|
|
g_signal_new ("format-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpDrawableClass, format_changed),
|
2020-01-12 18:06:05 +08:00
|
|
|
NULL, NULL, NULL,
|
2018-12-28 15:06:40 +08:00
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2003-05-21 19:34:00 +08:00
|
|
|
gimp_drawable_signals[ALPHA_CHANGED] =
|
2005-05-28 00:51:39 +08:00
|
|
|
g_signal_new ("alpha-changed",
|
2004-07-14 18:31:59 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpDrawableClass, alpha_changed),
|
2020-01-12 18:06:05 +08:00
|
|
|
NULL, NULL, NULL,
|
2004-07-14 18:31:59 +08:00
|
|
|
G_TYPE_NONE, 0);
|
2003-05-21 19:34:00 +08:00
|
|
|
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
gimp_drawable_signals[BOUNDING_BOX_CHANGED] =
|
|
|
|
g_signal_new ("bounding-box-changed",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpDrawableClass, bounding_box_changed),
|
2020-01-12 18:06:05 +08:00
|
|
|
NULL, NULL, NULL,
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
app: exclude invisible filters from filter-stack graph
Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change. This has two main
disadvantages:
- There's no easy, generic way to toggle a filter's effect,
especially one that is not subclassed, since GimpFilter only
takes care of the case where visibility becomes FALSE, and does
nothing by itself when it becomes TRUE again.
- While GimpDrawable does handle the visibility => TRUE case, it
doesn't disconnect the filter's input from its mode and
(potentially) source nodes when it becomes invisible. As a
result, while none of the drawable's graph is processed as part
of the composition when not visible, the mode and source nodes
do get invalidated when the filter's input is invalidated, such
as while painting on a layer below the drawable. This is
particularly bad for pass-through groups, since their source
node can be an arbitrarily complex graph, whose invlidation
incurs a nontrivial overhead.
Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again. This solves both of the above problems, as
well as simplifies the code.
2017-12-06 03:30:01 +08:00
|
|
|
object_class->dispose = gimp_drawable_dispose;
|
|
|
|
object_class->finalize = gimp_drawable_finalize;
|
|
|
|
object_class->set_property = gimp_drawable_set_property;
|
|
|
|
object_class->get_property = gimp_drawable_get_property;
|
|
|
|
|
|
|
|
gimp_object_class->get_memsize = gimp_drawable_get_memsize;
|
|
|
|
|
|
|
|
viewable_class->get_size = gimp_drawable_get_size;
|
|
|
|
viewable_class->get_new_preview = gimp_drawable_get_new_preview;
|
|
|
|
viewable_class->get_new_pixbuf = gimp_drawable_get_new_pixbuf;
|
app: when freezing a drawable's preview, freeze ancestors' previews
Add GimpViewable::preview_{freeze,thaw}() virtual functions, which
get called when the viewable's preview is frozen/thawed. Implement
the functions in GimpDrawable, recursively freezing the parent
drawable's preview (or the image's preview, for top-level
drawables) while the drawable's preview is frozen. For layer
masks, freeze the associated layer's parent.
This avoids updating layer-group/image previews while painting on,
or applying a filter to, a descendant layer. This both reduces
lag, and fixes a discrepancy between the layer's preview, which
isn't updated, and its parents' previews.
2019-03-29 00:03:49 +08:00
|
|
|
viewable_class->preview_freeze = gimp_drawable_preview_freeze;
|
|
|
|
viewable_class->preview_thaw = gimp_drawable_preview_thaw;
|
app: exclude invisible filters from filter-stack graph
Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change. This has two main
disadvantages:
- There's no easy, generic way to toggle a filter's effect,
especially one that is not subclassed, since GimpFilter only
takes care of the case where visibility becomes FALSE, and does
nothing by itself when it becomes TRUE again.
- While GimpDrawable does handle the visibility => TRUE case, it
doesn't disconnect the filter's input from its mode and
(potentially) source nodes when it becomes invisible. As a
result, while none of the drawable's graph is processed as part
of the composition when not visible, the mode and source nodes
do get invalidated when the filter's input is invalidated, such
as while painting on a layer below the drawable. This is
particularly bad for pass-through groups, since their source
node can be an arbitrarily complex graph, whose invlidation
incurs a nontrivial overhead.
Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again. This solves both of the above problems, as
well as simplifies the code.
2017-12-06 03:30:01 +08:00
|
|
|
|
|
|
|
filter_class->get_node = gimp_drawable_get_node;
|
|
|
|
|
|
|
|
item_class->removed = gimp_drawable_removed;
|
|
|
|
item_class->duplicate = gimp_drawable_duplicate;
|
|
|
|
item_class->scale = gimp_drawable_scale;
|
|
|
|
item_class->resize = gimp_drawable_resize;
|
|
|
|
item_class->flip = gimp_drawable_flip;
|
|
|
|
item_class->rotate = gimp_drawable_rotate;
|
|
|
|
item_class->transform = gimp_drawable_transform;
|
|
|
|
|
|
|
|
klass->update = gimp_drawable_real_update;
|
2018-12-28 15:06:40 +08:00
|
|
|
klass->format_changed = NULL;
|
app: exclude invisible filters from filter-stack graph
Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change. This has two main
disadvantages:
- There's no easy, generic way to toggle a filter's effect,
especially one that is not subclassed, since GimpFilter only
takes care of the case where visibility becomes FALSE, and does
nothing by itself when it becomes TRUE again.
- While GimpDrawable does handle the visibility => TRUE case, it
doesn't disconnect the filter's input from its mode and
(potentially) source nodes when it becomes invisible. As a
result, while none of the drawable's graph is processed as part
of the composition when not visible, the mode and source nodes
do get invalidated when the filter's input is invalidated, such
as while painting on a layer below the drawable. This is
particularly bad for pass-through groups, since their source
node can be an arbitrarily complex graph, whose invlidation
incurs a nontrivial overhead.
Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again. This solves both of the above problems, as
well as simplifies the code.
2017-12-06 03:30:01 +08:00
|
|
|
klass->alpha_changed = NULL;
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
klass->bounding_box_changed = NULL;
|
app: exclude invisible filters from filter-stack graph
Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change. This has two main
disadvantages:
- There's no easy, generic way to toggle a filter's effect,
especially one that is not subclassed, since GimpFilter only
takes care of the case where visibility becomes FALSE, and does
nothing by itself when it becomes TRUE again.
- While GimpDrawable does handle the visibility => TRUE case, it
doesn't disconnect the filter's input from its mode and
(potentially) source nodes when it becomes invisible. As a
result, while none of the drawable's graph is processed as part
of the composition when not visible, the mode and source nodes
do get invalidated when the filter's input is invalidated, such
as while painting on a layer below the drawable. This is
particularly bad for pass-through groups, since their source
node can be an arbitrarily complex graph, whose invlidation
incurs a nontrivial overhead.
Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again. This solves both of the above problems, as
well as simplifies the code.
2017-12-06 03:30:01 +08:00
|
|
|
klass->estimate_memsize = gimp_drawable_real_estimate_memsize;
|
app: add gimp_drawable_update_all()
Add a new GimpDrawable::update_all() virtual function, and a
corresponding gimp_drawable_update_all() function, which updates
the full contents of the drawable. Unlike calling
`gimp_drawable_update (drawable, 0, 0, -1, -1)`, which updates the
entire drawable area, gimp_drawable_update_all() only updates the
area that has actual content. While the default implentation does
simply update the entire drawable area, GimpGroupLayer overrides
this function to recursively update its child layers, rather than
the its entire area.
2019-06-10 15:42:07 +08:00
|
|
|
klass->update_all = gimp_drawable_real_update_all;
|
app: exclude invisible filters from filter-stack graph
Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change. This has two main
disadvantages:
- There's no easy, generic way to toggle a filter's effect,
especially one that is not subclassed, since GimpFilter only
takes care of the case where visibility becomes FALSE, and does
nothing by itself when it becomes TRUE again.
- While GimpDrawable does handle the visibility => TRUE case, it
doesn't disconnect the filter's input from its mode and
(potentially) source nodes when it becomes invisible. As a
result, while none of the drawable's graph is processed as part
of the composition when not visible, the mode and source nodes
do get invalidated when the filter's input is invalidated, such
as while painting on a layer below the drawable. This is
particularly bad for pass-through groups, since their source
node can be an arbitrarily complex graph, whose invlidation
incurs a nontrivial overhead.
Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again. This solves both of the above problems, as
well as simplifies the code.
2017-12-06 03:30:01 +08:00
|
|
|
klass->invalidate_boundary = NULL;
|
|
|
|
klass->get_active_components = NULL;
|
2019-02-17 01:56:20 +08:00
|
|
|
klass->get_active_mask = gimp_drawable_real_get_active_mask;
|
2020-01-17 17:24:31 +08:00
|
|
|
klass->supports_alpha = gimp_drawable_real_supports_alpha;
|
app: exclude invisible filters from filter-stack graph
Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change. This has two main
disadvantages:
- There's no easy, generic way to toggle a filter's effect,
especially one that is not subclassed, since GimpFilter only
takes care of the case where visibility becomes FALSE, and does
nothing by itself when it becomes TRUE again.
- While GimpDrawable does handle the visibility => TRUE case, it
doesn't disconnect the filter's input from its mode and
(potentially) source nodes when it becomes invisible. As a
result, while none of the drawable's graph is processed as part
of the composition when not visible, the mode and source nodes
do get invalidated when the filter's input is invalidated, such
as while painting on a layer below the drawable. This is
particularly bad for pass-through groups, since their source
node can be an arbitrarily complex graph, whose invlidation
incurs a nontrivial overhead.
Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again. This solves both of the above problems, as
well as simplifies the code.
2017-12-06 03:30:01 +08:00
|
|
|
klass->convert_type = gimp_drawable_real_convert_type;
|
|
|
|
klass->apply_buffer = gimp_drawable_real_apply_buffer;
|
|
|
|
klass->get_buffer = gimp_drawable_real_get_buffer;
|
|
|
|
klass->set_buffer = gimp_drawable_real_set_buffer;
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
klass->get_bounding_box = gimp_drawable_real_get_bounding_box;
|
app: exclude invisible filters from filter-stack graph
Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change. This has two main
disadvantages:
- There's no easy, generic way to toggle a filter's effect,
especially one that is not subclassed, since GimpFilter only
takes care of the case where visibility becomes FALSE, and does
nothing by itself when it becomes TRUE again.
- While GimpDrawable does handle the visibility => TRUE case, it
doesn't disconnect the filter's input from its mode and
(potentially) source nodes when it becomes invisible. As a
result, while none of the drawable's graph is processed as part
of the composition when not visible, the mode and source nodes
do get invalidated when the filter's input is invalidated, such
as while painting on a layer below the drawable. This is
particularly bad for pass-through groups, since their source
node can be an arbitrarily complex graph, whose invlidation
incurs a nontrivial overhead.
Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again. This solves both of the above problems, as
well as simplifies the code.
2017-12-06 03:30:01 +08:00
|
|
|
klass->push_undo = gimp_drawable_real_push_undo;
|
|
|
|
klass->swap_pixels = gimp_drawable_real_swap_pixels;
|
|
|
|
klass->get_source_node = gimp_drawable_real_get_source_node;
|
2009-02-04 07:57:11 +08:00
|
|
|
|
2013-09-05 16:37:09 +08:00
|
|
|
g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
|
1998-06-30 23:31:32 +08:00
|
|
|
}
|
|
|
|
|
2001-01-20 21:21:49 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_init (GimpDrawable *drawable)
|
|
|
|
{
|
app, libgimp*, modules: don't use g_type_class_add_private() ...
... and G_TYPE_INSTANCE_GET_PRIVATE()
g_type_class_add_private() and G_TYPE_INSTANCE_GET_PRIVATE() were
deprecated in GLib 2.58. Instead, use
G_DEFINE_[ABSTRACT_]TYPE_WITH_PRIVATE(), and
G_ADD_PRIVATE[_DYNAMIC](), and the implictly-defined
foo_get_instance_private() functions, all of which are available in
the GLib versions we depend on.
This commit only covers types registered using one of the
G_DEFINE_FOO() macros (i.e., most types), but not types with a
custom registration function, of which we still have a few -- GLib
currently only provides a (non-deprecated) public API for adding a
private struct using the G_DEFINE_FOO() macros.
Note that this commit was 99% auto-generated (because I'm not
*that* crazy :), so if there are any style mismatches... we'll have
to live with them for now.
2018-09-19 00:09:39 +08:00
|
|
|
drawable->private = gimp_drawable_get_instance_private (drawable);
|
2013-04-12 01:06:23 +08:00
|
|
|
|
|
|
|
drawable->private->filter_stack = gimp_filter_stack_new (GIMP_TYPE_FILTER);
|
2001-01-20 21:21:49 +08:00
|
|
|
}
|
|
|
|
|
2006-11-25 06:41:03 +08:00
|
|
|
/* sorry for the evil casts */
|
|
|
|
|
2004-07-14 07:04:05 +08:00
|
|
|
static void
|
2016-05-01 05:41:32 +08:00
|
|
|
gimp_color_managed_iface_init (GimpColorManagedInterface *iface)
|
|
|
|
{
|
|
|
|
iface->get_icc_profile = gimp_drawable_get_icc_profile;
|
|
|
|
iface->get_color_profile = gimp_drawable_get_color_profile;
|
|
|
|
iface->profile_changed = gimp_drawable_profile_changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_pickable_iface_init (GimpPickableInterface *iface)
|
2004-07-14 07:04:05 +08:00
|
|
|
{
|
2012-03-18 23:20:01 +08:00
|
|
|
iface->get_image = (GimpImage * (*) (GimpPickable *pickable)) gimp_item_get_image;
|
|
|
|
iface->get_format = (const Babl * (*) (GimpPickable *pickable)) gimp_drawable_get_format;
|
|
|
|
iface->get_format_with_alpha = (const Babl * (*) (GimpPickable *pickable)) gimp_drawable_get_format_with_alpha;
|
2012-03-21 07:42:44 +08:00
|
|
|
iface->get_buffer = (GeglBuffer * (*) (GimpPickable *pickable)) gimp_drawable_get_buffer;
|
2012-03-18 23:20:01 +08:00
|
|
|
iface->get_pixel_at = gimp_drawable_get_pixel_at;
|
2018-05-19 02:57:19 +08:00
|
|
|
iface->get_pixel_average = gimp_drawable_get_pixel_average;
|
2004-07-14 07:04:05 +08:00
|
|
|
}
|
|
|
|
|
2001-01-20 21:21:49 +08:00
|
|
|
static void
|
2011-09-24 01:55:24 +08:00
|
|
|
gimp_drawable_dispose (GObject *object)
|
2001-01-20 21:21:49 +08:00
|
|
|
{
|
2003-09-02 21:43:26 +08:00
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (object);
|
2001-01-20 21:21:49 +08:00
|
|
|
|
2011-09-24 01:55:24 +08:00
|
|
|
if (gimp_drawable_get_floating_sel (drawable))
|
|
|
|
gimp_drawable_detach_floating_sel (drawable);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_drawable_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (object);
|
2009-01-27 06:05:07 +08:00
|
|
|
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
while (drawable->private->paint_count)
|
|
|
|
gimp_drawable_end_paint (drawable);
|
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&drawable->private->buffer);
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
g_clear_object (&drawable->private->format_profile);
|
2012-03-15 09:42:59 +08:00
|
|
|
|
2012-03-23 02:10:12 +08:00
|
|
|
gimp_drawable_free_shadow_buffer (drawable);
|
2012-03-22 04:26:05 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&drawable->private->source_node);
|
2017-04-22 03:21:10 +08:00
|
|
|
g_clear_object (&drawable->private->buffer_source_node);
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&drawable->private->filter_stack);
|
2013-04-12 01:06:23 +08:00
|
|
|
|
2001-08-11 22:39:19 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
2001-01-20 21:21:49 +08:00
|
|
|
}
|
|
|
|
|
2012-11-12 17:55:41 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
switch (property_id)
|
|
|
|
{
|
2013-09-05 16:37:09 +08:00
|
|
|
case PROP_BUFFER:
|
2012-11-12 17:55:41 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_drawable_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
2013-09-05 16:37:09 +08:00
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (object);
|
|
|
|
|
2012-11-12 17:55:41 +08:00
|
|
|
switch (property_id)
|
|
|
|
{
|
2013-09-05 16:37:09 +08:00
|
|
|
case PROP_BUFFER:
|
|
|
|
g_value_set_object (value, drawable->private->buffer);
|
|
|
|
break;
|
|
|
|
|
2012-11-12 17:55:41 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-17 01:51:36 +08:00
|
|
|
static gint64
|
2003-08-25 18:49:33 +08:00
|
|
|
gimp_drawable_get_memsize (GimpObject *object,
|
2003-11-17 01:51:36 +08:00
|
|
|
gint64 *gui_size)
|
2002-01-31 00:14:26 +08:00
|
|
|
{
|
2004-07-14 18:31:59 +08:00
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (object);
|
|
|
|
gint64 memsize = 0;
|
2002-01-31 00:14:26 +08:00
|
|
|
|
2012-03-22 07:07:48 +08:00
|
|
|
memsize += gimp_gegl_buffer_get_memsize (gimp_drawable_get_buffer (drawable));
|
2012-03-23 02:10:12 +08:00
|
|
|
memsize += gimp_gegl_buffer_get_memsize (drawable->private->shadow);
|
2002-01-31 00:14:26 +08:00
|
|
|
|
2003-08-25 18:49:33 +08:00
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
|
|
gui_size);
|
2002-01-31 00:14:26 +08:00
|
|
|
}
|
|
|
|
|
2005-05-25 18:05:17 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_drawable_get_size (GimpViewable *viewable,
|
|
|
|
gint *width,
|
|
|
|
gint *height)
|
|
|
|
{
|
|
|
|
GimpItem *item = GIMP_ITEM (viewable);
|
|
|
|
|
2008-11-03 08:09:01 +08:00
|
|
|
*width = gimp_item_get_width (item);
|
|
|
|
*height = gimp_item_get_height (item);
|
2005-05-25 18:05:17 +08:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
app: when freezing a drawable's preview, freeze ancestors' previews
Add GimpViewable::preview_{freeze,thaw}() virtual functions, which
get called when the viewable's preview is frozen/thawed. Implement
the functions in GimpDrawable, recursively freezing the parent
drawable's preview (or the image's preview, for top-level
drawables) while the drawable's preview is frozen. For layer
masks, freeze the associated layer's parent.
This avoids updating layer-group/image previews while painting on,
or applying a filter to, a descendant layer. This both reduces
lag, and fixes a discrepancy between the layer's preview, which
isn't updated, and its parents' previews.
2019-03-29 00:03:49 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_preview_freeze (GimpViewable *viewable)
|
|
|
|
{
|
|
|
|
GimpViewable *parent = gimp_viewable_get_parent (viewable);
|
|
|
|
|
2019-03-29 00:35:32 +08:00
|
|
|
if (! parent && gimp_item_is_attached (GIMP_ITEM (viewable)))
|
app: when freezing a drawable's preview, freeze ancestors' previews
Add GimpViewable::preview_{freeze,thaw}() virtual functions, which
get called when the viewable's preview is frozen/thawed. Implement
the functions in GimpDrawable, recursively freezing the parent
drawable's preview (or the image's preview, for top-level
drawables) while the drawable's preview is frozen. For layer
masks, freeze the associated layer's parent.
This avoids updating layer-group/image previews while painting on,
or applying a filter to, a descendant layer. This both reduces
lag, and fixes a discrepancy between the layer's preview, which
isn't updated, and its parents' previews.
2019-03-29 00:03:49 +08:00
|
|
|
parent = GIMP_VIEWABLE (gimp_item_get_image (GIMP_ITEM (viewable)));
|
|
|
|
|
2019-03-29 00:35:32 +08:00
|
|
|
if (parent)
|
|
|
|
gimp_viewable_preview_freeze (parent);
|
app: when freezing a drawable's preview, freeze ancestors' previews
Add GimpViewable::preview_{freeze,thaw}() virtual functions, which
get called when the viewable's preview is frozen/thawed. Implement
the functions in GimpDrawable, recursively freezing the parent
drawable's preview (or the image's preview, for top-level
drawables) while the drawable's preview is frozen. For layer
masks, freeze the associated layer's parent.
This avoids updating layer-group/image previews while painting on,
or applying a filter to, a descendant layer. This both reduces
lag, and fixes a discrepancy between the layer's preview, which
isn't updated, and its parents' previews.
2019-03-29 00:03:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_drawable_preview_thaw (GimpViewable *viewable)
|
|
|
|
{
|
|
|
|
GimpViewable *parent = gimp_viewable_get_parent (viewable);
|
|
|
|
|
2019-03-29 00:35:32 +08:00
|
|
|
if (! parent && gimp_item_is_attached (GIMP_ITEM (viewable)))
|
app: when freezing a drawable's preview, freeze ancestors' previews
Add GimpViewable::preview_{freeze,thaw}() virtual functions, which
get called when the viewable's preview is frozen/thawed. Implement
the functions in GimpDrawable, recursively freezing the parent
drawable's preview (or the image's preview, for top-level
drawables) while the drawable's preview is frozen. For layer
masks, freeze the associated layer's parent.
This avoids updating layer-group/image previews while painting on,
or applying a filter to, a descendant layer. This both reduces
lag, and fixes a discrepancy between the layer's preview, which
isn't updated, and its parents' previews.
2019-03-29 00:03:49 +08:00
|
|
|
parent = GIMP_VIEWABLE (gimp_item_get_image (GIMP_ITEM (viewable)));
|
|
|
|
|
2019-03-29 00:35:32 +08:00
|
|
|
if (parent)
|
|
|
|
gimp_viewable_preview_thaw (parent);
|
app: when freezing a drawable's preview, freeze ancestors' previews
Add GimpViewable::preview_{freeze,thaw}() virtual functions, which
get called when the viewable's preview is frozen/thawed. Implement
the functions in GimpDrawable, recursively freezing the parent
drawable's preview (or the image's preview, for top-level
drawables) while the drawable's preview is frozen. For layer
masks, freeze the associated layer's parent.
This avoids updating layer-group/image previews while painting on,
or applying a filter to, a descendant layer. This both reduces
lag, and fixes a discrepancy between the layer's preview, which
isn't updated, and its parents' previews.
2019-03-29 00:03:49 +08:00
|
|
|
}
|
|
|
|
|
2013-04-11 08:54:42 +08:00
|
|
|
static GeglNode *
|
|
|
|
gimp_drawable_get_node (GimpFilter *filter)
|
|
|
|
{
|
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (filter);
|
|
|
|
GeglNode *node;
|
|
|
|
GeglNode *input;
|
|
|
|
GeglNode *output;
|
|
|
|
|
|
|
|
node = GIMP_FILTER_CLASS (parent_class)->get_node (filter);
|
|
|
|
|
|
|
|
g_warn_if_fail (drawable->private->mode_node == NULL);
|
|
|
|
|
|
|
|
drawable->private->mode_node =
|
|
|
|
gegl_node_new_child (node,
|
2017-01-11 07:28:57 +08:00
|
|
|
"operation", "gimp:normal",
|
2013-04-11 08:54:42 +08:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
input = gegl_node_get_input_proxy (node, "input");
|
|
|
|
output = gegl_node_get_output_proxy (node, "output");
|
|
|
|
|
2023-06-13 23:05:02 +08:00
|
|
|
gegl_node_link (input, drawable->private->mode_node);
|
|
|
|
gegl_node_link (drawable->private->mode_node, output);
|
2013-04-11 08:54:42 +08:00
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2008-04-22 01:20:51 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_removed (GimpItem *item)
|
|
|
|
{
|
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (item);
|
|
|
|
|
2012-03-23 02:10:12 +08:00
|
|
|
gimp_drawable_free_shadow_buffer (drawable);
|
2008-04-22 01:20:51 +08:00
|
|
|
|
|
|
|
if (GIMP_ITEM_CLASS (parent_class)->removed)
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->removed (item);
|
|
|
|
}
|
|
|
|
|
2003-02-11 21:52:47 +08:00
|
|
|
static GimpItem *
|
|
|
|
gimp_drawable_duplicate (GimpItem *item,
|
2008-01-08 19:46:15 +08:00
|
|
|
GType new_type)
|
2001-12-13 07:48:18 +08:00
|
|
|
{
|
2005-12-23 09:15:19 +08:00
|
|
|
GimpItem *new_item;
|
2001-12-13 07:48:18 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL);
|
|
|
|
|
2008-01-08 19:46:15 +08:00
|
|
|
new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type);
|
2003-02-11 21:52:47 +08:00
|
|
|
|
2005-12-23 09:15:19 +08:00
|
|
|
if (GIMP_IS_DRAWABLE (new_item))
|
|
|
|
{
|
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (item);
|
|
|
|
GimpDrawable *new_drawable = GIMP_DRAWABLE (new_item);
|
2018-02-10 18:26:26 +08:00
|
|
|
GeglBuffer *new_buffer;
|
2011-02-01 17:46:53 +08:00
|
|
|
|
2019-07-31 01:25:54 +08:00
|
|
|
new_buffer = gimp_gegl_buffer_dup (gimp_drawable_get_buffer (drawable));
|
2005-12-23 09:15:19 +08:00
|
|
|
|
2018-02-10 18:26:26 +08:00
|
|
|
gimp_drawable_set_buffer (new_drawable, FALSE, NULL, new_buffer);
|
|
|
|
g_object_unref (new_buffer);
|
2005-12-23 09:15:19 +08:00
|
|
|
}
|
2001-12-13 07:48:18 +08:00
|
|
|
|
2003-02-11 21:52:47 +08:00
|
|
|
return new_item;
|
|
|
|
}
|
|
|
|
|
2003-05-07 19:09:00 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_scale (GimpItem *item,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint new_offset_x,
|
|
|
|
gint new_offset_y,
|
2004-02-09 08:09:20 +08:00
|
|
|
GimpInterpolationType interpolation_type,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress)
|
2003-05-07 19:09:00 +08:00
|
|
|
{
|
2004-03-16 04:05:31 +08:00
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (item);
|
2012-03-22 04:46:03 +08:00
|
|
|
GeglBuffer *new_buffer;
|
2003-05-07 19:09:00 +08:00
|
|
|
|
2012-06-21 03:44:09 +08:00
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
new_width, new_height),
|
|
|
|
gimp_drawable_get_format (drawable));
|
2003-05-07 19:09:00 +08:00
|
|
|
|
2012-11-01 06:47:45 +08:00
|
|
|
gimp_gegl_apply_scale (gimp_drawable_get_buffer (drawable),
|
|
|
|
progress, C_("undo-type", "Scale"),
|
|
|
|
new_buffer,
|
|
|
|
interpolation_type,
|
|
|
|
((gdouble) new_width /
|
|
|
|
gimp_item_get_width (item)),
|
|
|
|
((gdouble) new_height /
|
|
|
|
gimp_item_get_height (item)));
|
2003-05-07 19:09:00 +08:00
|
|
|
|
2012-03-22 04:46:03 +08:00
|
|
|
gimp_drawable_set_buffer_full (drawable, gimp_item_is_attached (item), NULL,
|
2012-03-22 06:37:16 +08:00
|
|
|
new_buffer,
|
2019-08-02 02:41:47 +08:00
|
|
|
GEGL_RECTANGLE (new_offset_x, new_offset_y,
|
|
|
|
0, 0),
|
2018-08-04 00:58:03 +08:00
|
|
|
TRUE);
|
2012-03-22 04:46:03 +08:00
|
|
|
g_object_unref (new_buffer);
|
2003-05-07 19:09:00 +08:00
|
|
|
}
|
|
|
|
|
2003-05-07 21:01:17 +08:00
|
|
|
static void
|
2016-10-10 06:02:16 +08:00
|
|
|
gimp_drawable_resize (GimpItem *item,
|
|
|
|
GimpContext *context,
|
|
|
|
GimpFillType fill_type,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y)
|
2003-05-07 21:01:17 +08:00
|
|
|
{
|
2004-03-16 04:05:31 +08:00
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (item);
|
2012-03-21 17:10:20 +08:00
|
|
|
GeglBuffer *new_buffer;
|
2003-05-14 23:32:07 +08:00
|
|
|
gint new_offset_x;
|
|
|
|
gint new_offset_y;
|
|
|
|
gint copy_x, copy_y;
|
|
|
|
gint copy_width, copy_height;
|
2013-11-16 16:38:29 +08:00
|
|
|
gboolean intersect;
|
2003-05-07 21:01:17 +08:00
|
|
|
|
2004-11-23 17:32:54 +08:00
|
|
|
/* if the size doesn't change, this is a nop */
|
2008-11-03 08:09:01 +08:00
|
|
|
if (new_width == gimp_item_get_width (item) &&
|
|
|
|
new_height == gimp_item_get_height (item) &&
|
2013-11-16 16:38:29 +08:00
|
|
|
offset_x == 0 &&
|
2004-11-26 22:45:10 +08:00
|
|
|
offset_y == 0)
|
2004-11-23 17:32:54 +08:00
|
|
|
return;
|
|
|
|
|
2008-12-28 20:43:07 +08:00
|
|
|
new_offset_x = gimp_item_get_offset_x (item) - offset_x;
|
|
|
|
new_offset_y = gimp_item_get_offset_y (item) - offset_y;
|
2003-05-07 21:01:17 +08:00
|
|
|
|
2013-11-16 16:38:29 +08:00
|
|
|
intersect = gimp_rectangle_intersect (gimp_item_get_offset_x (item),
|
|
|
|
gimp_item_get_offset_y (item),
|
|
|
|
gimp_item_get_width (item),
|
|
|
|
gimp_item_get_height (item),
|
|
|
|
new_offset_x,
|
|
|
|
new_offset_y,
|
|
|
|
new_width,
|
|
|
|
new_height,
|
|
|
|
©_x,
|
|
|
|
©_y,
|
|
|
|
©_width,
|
|
|
|
©_height);
|
2003-05-07 21:01:17 +08:00
|
|
|
|
2012-06-21 03:44:09 +08:00
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
new_width, new_height),
|
|
|
|
gimp_drawable_get_format (drawable));
|
2012-03-16 09:21:26 +08:00
|
|
|
|
2013-11-16 16:38:29 +08:00
|
|
|
if (! intersect ||
|
|
|
|
copy_width != new_width ||
|
2003-05-14 23:32:07 +08:00
|
|
|
copy_height != new_height)
|
2003-05-07 21:01:17 +08:00
|
|
|
{
|
2016-10-10 06:02:16 +08:00
|
|
|
/* Clear the new buffer if needed */
|
2003-05-14 23:32:07 +08:00
|
|
|
|
2016-10-10 06:02:16 +08:00
|
|
|
GimpRGB color;
|
|
|
|
GimpPattern *pattern;
|
2003-05-07 21:01:17 +08:00
|
|
|
|
2016-10-10 06:02:16 +08:00
|
|
|
gimp_get_fill_params (context, fill_type, &color, &pattern, NULL);
|
|
|
|
gimp_drawable_fill_buffer (drawable, new_buffer,
|
|
|
|
&color, pattern, 0, 0);
|
2003-05-07 21:01:17 +08:00
|
|
|
}
|
|
|
|
|
2013-11-16 16:38:29 +08:00
|
|
|
if (intersect && copy_width && copy_height)
|
2003-05-07 21:01:17 +08:00
|
|
|
{
|
2012-03-16 09:21:26 +08:00
|
|
|
/* Copy the pixels in the intersection */
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (
|
|
|
|
gimp_drawable_get_buffer (drawable),
|
|
|
|
GEGL_RECTANGLE (copy_x - gimp_item_get_offset_x (item),
|
|
|
|
copy_y - gimp_item_get_offset_y (item),
|
|
|
|
copy_width,
|
|
|
|
copy_height), GEGL_ABYSS_NONE,
|
|
|
|
new_buffer,
|
|
|
|
GEGL_RECTANGLE (copy_x - new_offset_x,
|
|
|
|
copy_y - new_offset_y, 0, 0));
|
2003-05-07 21:01:17 +08:00
|
|
|
}
|
|
|
|
|
2023-06-17 19:07:40 +08:00
|
|
|
gimp_drawable_set_buffer_full (drawable,
|
|
|
|
gimp_item_is_attached (item) &&
|
2023-09-05 06:16:17 +08:00
|
|
|
drawable->private->push_resize_undo,
|
2023-06-17 19:07:40 +08:00
|
|
|
NULL,
|
2012-03-22 06:37:16 +08:00
|
|
|
new_buffer,
|
2019-08-02 02:41:47 +08:00
|
|
|
GEGL_RECTANGLE (new_offset_x, new_offset_y,
|
|
|
|
0, 0),
|
2018-08-04 00:58:03 +08:00
|
|
|
TRUE);
|
2012-03-21 17:10:20 +08:00
|
|
|
g_object_unref (new_buffer);
|
2003-05-07 21:01:17 +08:00
|
|
|
}
|
|
|
|
|
2003-05-13 21:57:11 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_flip (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-05-13 21:57:11 +08:00
|
|
|
GimpOrientationType flip_type,
|
|
|
|
gdouble axis,
|
|
|
|
gboolean clip_result)
|
|
|
|
{
|
2016-05-09 00:35:40 +08:00
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (item);
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
GimpColorProfile *buffer_profile;
|
|
|
|
gint off_x, off_y;
|
|
|
|
gint new_off_x, new_off_y;
|
2003-05-13 21:57:11 +08:00
|
|
|
|
2008-11-03 07:03:29 +08:00
|
|
|
gimp_item_get_offset (item, &off_x, &off_y);
|
2003-05-13 21:57:11 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
buffer = gimp_drawable_transform_buffer_flip (drawable, context,
|
|
|
|
gimp_drawable_get_buffer (drawable),
|
|
|
|
off_x, off_y,
|
|
|
|
flip_type, axis,
|
|
|
|
clip_result,
|
2016-05-09 00:35:40 +08:00
|
|
|
&buffer_profile,
|
2012-03-21 21:30:47 +08:00
|
|
|
&new_off_x, &new_off_y);
|
2003-05-13 21:57:11 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
if (buffer)
|
2003-05-27 01:02:06 +08:00
|
|
|
{
|
2016-05-09 00:35:40 +08:00
|
|
|
gimp_drawable_transform_paste (drawable, buffer, buffer_profile,
|
2011-03-26 15:30:15 +08:00
|
|
|
new_off_x, new_off_y, FALSE);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_object_unref (buffer);
|
2003-05-27 01:02:06 +08:00
|
|
|
}
|
2003-05-13 21:57:11 +08:00
|
|
|
}
|
|
|
|
|
2003-05-20 18:36:29 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_rotate (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-05-20 18:36:29 +08:00
|
|
|
GimpRotationType rotate_type,
|
|
|
|
gdouble center_x,
|
|
|
|
gdouble center_y,
|
|
|
|
gboolean clip_result)
|
|
|
|
{
|
2016-05-09 00:35:40 +08:00
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (item);
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
GimpColorProfile *buffer_profile;
|
|
|
|
gint off_x, off_y;
|
|
|
|
gint new_off_x, new_off_y;
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2008-11-03 07:03:29 +08:00
|
|
|
gimp_item_get_offset (item, &off_x, &off_y);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
buffer = gimp_drawable_transform_buffer_rotate (drawable, context,
|
|
|
|
gimp_drawable_get_buffer (drawable),
|
|
|
|
off_x, off_y,
|
|
|
|
rotate_type, center_x, center_y,
|
|
|
|
clip_result,
|
2016-05-09 00:35:40 +08:00
|
|
|
&buffer_profile,
|
2012-03-21 21:30:47 +08:00
|
|
|
&new_off_x, &new_off_y);
|
2003-05-20 18:36:29 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
if (buffer)
|
2003-05-27 01:02:06 +08:00
|
|
|
{
|
2016-05-09 00:35:40 +08:00
|
|
|
gimp_drawable_transform_paste (drawable, buffer, buffer_profile,
|
2011-03-26 15:30:15 +08:00
|
|
|
new_off_x, new_off_y, FALSE);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_object_unref (buffer);
|
2003-05-27 01:02:06 +08:00
|
|
|
}
|
2003-05-20 18:36:29 +08:00
|
|
|
}
|
|
|
|
|
2003-05-13 21:57:11 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_transform (GimpItem *item,
|
2004-04-15 07:37:34 +08:00
|
|
|
GimpContext *context,
|
2003-07-07 21:50:48 +08:00
|
|
|
const GimpMatrix3 *matrix,
|
2003-05-13 21:57:11 +08:00
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interpolation_type,
|
2006-12-25 00:48:08 +08:00
|
|
|
GimpTransformResize clip_result,
|
2004-08-11 02:47:21 +08:00
|
|
|
GimpProgress *progress)
|
2003-05-13 21:57:11 +08:00
|
|
|
{
|
2016-05-09 00:35:40 +08:00
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (item);
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
GimpColorProfile *buffer_profile;
|
|
|
|
gint off_x, off_y;
|
|
|
|
gint new_off_x, new_off_y;
|
2003-05-13 21:57:11 +08:00
|
|
|
|
2008-11-03 07:03:29 +08:00
|
|
|
gimp_item_get_offset (item, &off_x, &off_y);
|
2003-05-13 21:57:11 +08:00
|
|
|
|
2012-03-21 21:30:47 +08:00
|
|
|
buffer = gimp_drawable_transform_buffer_affine (drawable, context,
|
|
|
|
gimp_drawable_get_buffer (drawable),
|
|
|
|
off_x, off_y,
|
|
|
|
matrix, direction,
|
|
|
|
interpolation_type,
|
|
|
|
clip_result,
|
2016-05-09 00:35:40 +08:00
|
|
|
&buffer_profile,
|
2012-03-21 21:30:47 +08:00
|
|
|
&new_off_x, &new_off_y,
|
|
|
|
progress);
|
|
|
|
|
|
|
|
if (buffer)
|
2003-05-27 01:02:06 +08:00
|
|
|
{
|
2016-05-09 00:35:40 +08:00
|
|
|
gimp_drawable_transform_paste (drawable, buffer, buffer_profile,
|
2011-03-26 23:50:38 +08:00
|
|
|
new_off_x, new_off_y, FALSE);
|
2012-03-21 21:30:47 +08:00
|
|
|
g_object_unref (buffer);
|
2003-05-27 01:02:06 +08:00
|
|
|
}
|
2003-05-13 21:57:11 +08:00
|
|
|
}
|
|
|
|
|
2016-05-01 05:41:32 +08:00
|
|
|
static const guint8 *
|
|
|
|
gimp_drawable_get_icc_profile (GimpColorManaged *managed,
|
|
|
|
gsize *len)
|
|
|
|
{
|
|
|
|
GimpColorProfile *profile = gimp_color_managed_get_color_profile (managed);
|
|
|
|
|
|
|
|
return gimp_color_profile_get_icc_profile (profile, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpColorProfile *
|
|
|
|
gimp_drawable_get_color_profile (GimpColorManaged *managed)
|
|
|
|
{
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (managed);
|
|
|
|
const Babl *format = gimp_drawable_get_format (drawable);
|
2016-05-01 05:41:32 +08:00
|
|
|
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
if (! drawable->private->format_profile)
|
|
|
|
drawable->private->format_profile =
|
|
|
|
gimp_babl_format_get_color_profile (format);
|
|
|
|
|
|
|
|
return drawable->private->format_profile;
|
2016-05-01 05:41:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_drawable_profile_changed (GimpColorManaged *managed)
|
|
|
|
{
|
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (managed));
|
|
|
|
}
|
|
|
|
|
2007-04-28 00:07:49 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_drawable_get_pixel_at (GimpPickable *pickable,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
2012-04-21 16:03:32 +08:00
|
|
|
const Babl *format,
|
|
|
|
gpointer pixel)
|
2007-04-28 00:07:49 +08:00
|
|
|
{
|
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (pickable);
|
|
|
|
|
|
|
|
/* do not make this a g_return_if_fail() */
|
2008-11-03 08:09:01 +08:00
|
|
|
if (x < 0 || x >= gimp_item_get_width (GIMP_ITEM (drawable)) ||
|
|
|
|
y < 0 || y >= gimp_item_get_height (GIMP_ITEM (drawable)))
|
2007-04-28 00:07:49 +08:00
|
|
|
return FALSE;
|
|
|
|
|
2012-03-21 07:42:44 +08:00
|
|
|
gegl_buffer_sample (gimp_drawable_get_buffer (drawable),
|
2012-04-21 16:03:32 +08:00
|
|
|
x, y, NULL, pixel, format,
|
2012-03-26 08:17:24 +08:00
|
|
|
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
|
2007-04-28 00:07:49 +08:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-05-19 02:57:19 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_get_pixel_average (GimpPickable *pickable,
|
|
|
|
const GeglRectangle *rect,
|
|
|
|
const Babl *format,
|
|
|
|
gpointer pixel)
|
|
|
|
{
|
|
|
|
GimpDrawable *drawable = GIMP_DRAWABLE (pickable);
|
|
|
|
|
|
|
|
return gimp_gegl_average_color (gimp_drawable_get_buffer (drawable),
|
|
|
|
rect, TRUE, GEGL_ABYSS_NONE, format, pixel);
|
|
|
|
}
|
|
|
|
|
To optimize duplicate and/or wrong image updates away, introduced new
2003-09-06 Michael Natterer <mitch@gimp.org>
To optimize duplicate and/or wrong image updates away, introduced
new policy that a child object must never explicitly update or
invalidate its parent object (just like the GUI is not updated
explicitly by the core):
* app/core/gimpdrawable.[ch]: added new signal
GimpDrawable::update(). Never update or invalidate the image when
the drawable is updated or invalidated.
(gimp_drawable_set_visible): don't gimp_drawable_update() the
drawable since its pixels have not changed.
* app/core/gimpimage.[ch]: connect to the "add" and "remove"
signals of the layers and channels containers. Also connect to the
"update" and "visibility_changed" signals of all drawables in
these containers (optimizes away updates issued by drawables which
are not yet added to the image and updates of the selection
mask). Also, don't propagate updates to the image if the emitting
drawable is invisible (optimizes away updates issued by invisible
drawables).
(gimp_image_add_layer,channel)
(gimp_image_remove_layer,channel): don't update the image since
that's done by our "add" and "remove" handlers now.
(gimp_image_position_layer,channel): update just the image, not
the drawable since its pixels have not changed.
(gimp_image_real_colormap_changed)
(gimp_image_set_component_visible): always call
gimp_image_update() *and* gimp_viewable_invalidate_preview() to
get everything updated, since update and invalidate of images are
not connected.
* app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't
update the drawable since (a) its pixels don't change and (b) the
image updates itself upon adding/removing now.
(undo_pop_layer_mod): replaced gimp_image_update() by
gimp_drawable_update() (just for consistency with other similar
functions).
* app/core/gimplayer.c: connect to "update" of the layer mask and
issue updates on the layer if the mask update has any effect on
the projection.
(gimp_layer_create_mask): don't set the mask's offsets here since
they may be different when we later add the mask to the layer.
* app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the
mask offsets here instead.
* app/core/gimpchannel.c (gimp_channel_translate): update the
channel even if push_undo == FALSE.
* app/paint/gimppaintcore.c (gimp_paint_core_finish)
* app/tools/gimpinktool.c (ink_finish): invalidate both the
drawable and the image preview since invalidating the drawable
doesn't invalidate the image any more.
* app/text/gimptextlayer.c (gimp_text_layer_render_now): also
update the new extents of the text layer, not only the old one.
(gimp_text_layer_render_layout): don't update the drawable since
gimp_drawable_fill() already updated it.
2003-09-07 04:06:53 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_real_update (GimpDrawable *drawable,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
|
|
|
{
|
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable));
|
|
|
|
}
|
|
|
|
|
2007-12-04 19:30:31 +08:00
|
|
|
static gint64
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_real_estimate_memsize (GimpDrawable *drawable,
|
|
|
|
GimpComponentType component_type,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
2007-12-04 19:30:31 +08:00
|
|
|
{
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
|
|
|
|
GimpTRCType trc = gimp_drawable_get_trc (drawable);
|
|
|
|
const Babl *format;
|
2014-06-15 05:12:22 +08:00
|
|
|
|
2014-08-15 15:23:02 +08:00
|
|
|
format = gimp_image_get_format (image,
|
|
|
|
gimp_drawable_get_base_type (drawable),
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
gimp_babl_precision (component_type, trc),
|
|
|
|
gimp_drawable_has_alpha (drawable),
|
|
|
|
NULL);
|
2012-04-25 19:35:37 +08:00
|
|
|
|
|
|
|
return (gint64) babl_format_get_bytes_per_pixel (format) * width * height;
|
2007-12-04 19:30:31 +08:00
|
|
|
}
|
|
|
|
|
app: add gimp_drawable_update_all()
Add a new GimpDrawable::update_all() virtual function, and a
corresponding gimp_drawable_update_all() function, which updates
the full contents of the drawable. Unlike calling
`gimp_drawable_update (drawable, 0, 0, -1, -1)`, which updates the
entire drawable area, gimp_drawable_update_all() only updates the
area that has actual content. While the default implentation does
simply update the entire drawable area, GimpGroupLayer overrides
this function to recursively update its child layers, rather than
the its entire area.
2019-06-10 15:42:07 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_real_update_all (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
gimp_drawable_update (drawable, 0, 0, -1, -1);
|
|
|
|
}
|
|
|
|
|
2019-02-17 01:56:20 +08:00
|
|
|
static GimpComponentMask
|
|
|
|
gimp_drawable_real_get_active_mask (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
/* Return all, because that skips the component mask op when painting */
|
|
|
|
return GIMP_COMPONENT_MASK_ALL;
|
|
|
|
}
|
|
|
|
|
2020-01-17 17:24:31 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_drawable_real_supports_alpha (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-10-14 03:46:56 +08:00
|
|
|
/* FIXME: this default impl is currently unused because no subclass
|
2016-04-29 06:42:42 +08:00
|
|
|
* chains up. the goal is to handle the almost identical subclass code
|
2012-10-14 03:46:56 +08:00
|
|
|
* here again.
|
|
|
|
*/
|
2009-09-12 03:23:35 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_real_convert_type (GimpDrawable *drawable,
|
|
|
|
GimpImage *dest_image,
|
2012-10-14 04:56:32 +08:00
|
|
|
const Babl *new_format,
|
2018-08-06 04:19:17 +08:00
|
|
|
GimpColorProfile *src_profile,
|
2016-04-29 06:42:42 +08:00
|
|
|
GimpColorProfile *dest_profile,
|
2016-11-08 03:41:39 +08:00
|
|
|
GeglDitherMethod layer_dither_type,
|
|
|
|
GeglDitherMethod mask_dither_type,
|
2015-10-22 04:22:30 +08:00
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress)
|
2009-09-12 03:23:35 +08:00
|
|
|
{
|
2012-04-12 00:50:57 +08:00
|
|
|
GeglBuffer *dest_buffer;
|
2009-09-12 03:23:35 +08:00
|
|
|
|
2012-04-12 00:50:57 +08:00
|
|
|
dest_buffer =
|
2012-06-21 03:44:09 +08:00
|
|
|
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
gimp_item_get_width (GIMP_ITEM (drawable)),
|
|
|
|
gimp_item_get_height (GIMP_ITEM (drawable))),
|
2015-08-16 21:47:43 +08:00
|
|
|
new_format);
|
2012-03-18 05:53:17 +08:00
|
|
|
|
2018-08-06 04:19:17 +08:00
|
|
|
gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable), NULL,
|
|
|
|
GEGL_ABYSS_NONE,
|
|
|
|
dest_buffer, NULL);
|
2012-04-12 00:50:57 +08:00
|
|
|
|
|
|
|
gimp_drawable_set_buffer (drawable, push_undo, NULL, dest_buffer);
|
|
|
|
g_object_unref (dest_buffer);
|
2009-09-12 03:23:35 +08:00
|
|
|
}
|
|
|
|
|
2012-03-22 07:07:48 +08:00
|
|
|
static GeglBuffer *
|
|
|
|
gimp_drawable_real_get_buffer (GimpDrawable *drawable)
|
2007-12-18 19:20:23 +08:00
|
|
|
{
|
2012-03-22 07:07:48 +08:00
|
|
|
return drawable->private->buffer;
|
2007-12-18 19:20:23 +08:00
|
|
|
}
|
|
|
|
|
2004-03-13 21:56:09 +08:00
|
|
|
static void
|
2019-08-02 02:41:47 +08:00
|
|
|
gimp_drawable_real_set_buffer (GimpDrawable *drawable,
|
|
|
|
gboolean push_undo,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GeglBuffer *buffer,
|
|
|
|
const GeglRectangle *bounds)
|
2004-03-13 21:56:09 +08:00
|
|
|
{
|
2018-12-28 15:06:40 +08:00
|
|
|
GimpItem *item = GIMP_ITEM (drawable);
|
|
|
|
const Babl *old_format = NULL;
|
|
|
|
gint old_has_alpha = -1;
|
2004-03-15 23:37:12 +08:00
|
|
|
|
2015-06-24 22:26:45 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (drawable));
|
|
|
|
|
2004-03-16 01:53:55 +08:00
|
|
|
gimp_drawable_invalidate_boundary (drawable);
|
|
|
|
|
2004-03-16 04:58:07 +08:00
|
|
|
if (push_undo)
|
2018-02-14 23:29:35 +08:00
|
|
|
gimp_image_undo_push_drawable_mod (gimp_item_get_image (item), undo_desc,
|
|
|
|
drawable, FALSE);
|
2004-03-16 04:58:07 +08:00
|
|
|
|
2012-03-22 04:26:05 +08:00
|
|
|
if (drawable->private->buffer)
|
2018-12-28 15:06:40 +08:00
|
|
|
{
|
|
|
|
old_format = gimp_drawable_get_format (drawable);
|
|
|
|
old_has_alpha = gimp_drawable_has_alpha (drawable);
|
|
|
|
}
|
2004-03-13 21:56:09 +08:00
|
|
|
|
2018-06-01 18:59:52 +08:00
|
|
|
g_set_object (&drawable->private->buffer, buffer);
|
2023-06-03 01:43:39 +08:00
|
|
|
|
|
|
|
if (gimp_drawable_is_painting (drawable))
|
|
|
|
g_set_object (&drawable->private->paint_buffer, buffer);
|
|
|
|
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
g_clear_object (&drawable->private->format_profile);
|
2012-03-15 09:42:59 +08:00
|
|
|
|
2015-06-24 22:26:45 +08:00
|
|
|
if (drawable->private->buffer_source_node)
|
|
|
|
gegl_node_set (drawable->private->buffer_source_node,
|
|
|
|
"buffer", gimp_drawable_get_buffer (drawable),
|
|
|
|
NULL);
|
|
|
|
|
2019-08-02 02:41:47 +08:00
|
|
|
gimp_item_set_offset (item, bounds->x, bounds->y);
|
2018-02-14 23:29:35 +08:00
|
|
|
gimp_item_set_size (item,
|
2019-08-02 02:41:47 +08:00
|
|
|
bounds->width ? bounds->width :
|
|
|
|
gegl_buffer_get_width (buffer),
|
|
|
|
bounds->height ? bounds->height :
|
|
|
|
gegl_buffer_get_height (buffer));
|
2018-02-14 02:05:56 +08:00
|
|
|
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
gimp_drawable_update_bounding_box (drawable);
|
|
|
|
|
2018-12-28 15:06:40 +08:00
|
|
|
if (gimp_drawable_get_format (drawable) != old_format)
|
|
|
|
gimp_drawable_format_changed (drawable);
|
|
|
|
|
2018-02-14 23:29:35 +08:00
|
|
|
if (gimp_drawable_has_alpha (drawable) != old_has_alpha)
|
|
|
|
gimp_drawable_alpha_changed (drawable);
|
2008-10-10 04:44:23 +08:00
|
|
|
|
2013-09-05 16:37:09 +08:00
|
|
|
g_object_notify (G_OBJECT (drawable), "buffer");
|
2015-06-24 22:26:45 +08:00
|
|
|
|
|
|
|
g_object_thaw_notify (G_OBJECT (drawable));
|
2004-03-13 21:56:09 +08:00
|
|
|
}
|
|
|
|
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
static GeglRectangle
|
|
|
|
gimp_drawable_real_get_bounding_box (GimpDrawable *drawable)
|
|
|
|
{
|
2020-01-16 05:11:56 +08:00
|
|
|
return gegl_node_get_bounding_box (gimp_drawable_get_source_node (drawable));
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
}
|
|
|
|
|
2004-04-01 22:51:58 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_real_push_undo (GimpDrawable *drawable,
|
|
|
|
const gchar *undo_desc,
|
2012-03-22 21:13:17 +08:00
|
|
|
GeglBuffer *buffer,
|
2004-04-01 22:51:58 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
|
|
|
{
|
app: remove "Edit -> Fade..."
This commit completely removes the "Edit -> Fade..." feature,
because...
- The main reason is that "fade" requires us to keep two buffers,
instead of one, for each fadeable undo step, doubling (or worse,
since the extra buffer might have higher precision than the
drawable) the space consumed by these steps. This has notable
impact when editing large images. This overhead is incurred even
when not actually using "fade", and since it seems to be very
rarely used, this is too wasteful.
- "Fade" is broken in 2.10: when comitting a filter, we copy the
cached parts of the result into the apply buffer. However, the
result cache sits after the mode node, while the apply buffer
should contain the result of the filter *before* the mode node,
which can lead to wrong results in the general case.
- The same behavior can be trivially achieved "manually", by
duplicating the layer, editing the duplicate, and changing its
opacity/mode.
- If we really want this feature, now that most filters are GEGL
ops, it makes more sense to just add opacity/mode options to the
filter tool, instead of having this be a separate step.
2018-12-28 00:16:04 +08:00
|
|
|
GimpImage *image;
|
2018-12-02 15:36:17 +08:00
|
|
|
|
2012-03-22 21:13:17 +08:00
|
|
|
if (! buffer)
|
2004-04-01 22:51:58 +08:00
|
|
|
{
|
2018-12-02 15:36:17 +08:00
|
|
|
GeglBuffer *drawable_buffer = gimp_drawable_get_buffer (drawable);
|
|
|
|
GeglRectangle drawable_rect;
|
|
|
|
|
2019-07-30 21:09:36 +08:00
|
|
|
gegl_rectangle_align_to_buffer (
|
2018-12-02 15:36:17 +08:00
|
|
|
&drawable_rect,
|
|
|
|
GEGL_RECTANGLE (x, y, width, height),
|
2019-07-30 21:09:36 +08:00
|
|
|
drawable_buffer,
|
|
|
|
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
2018-12-02 15:36:17 +08:00
|
|
|
|
|
|
|
x = drawable_rect.x;
|
|
|
|
y = drawable_rect.y;
|
|
|
|
width = drawable_rect.width;
|
|
|
|
height = drawable_rect.height;
|
|
|
|
|
2012-05-21 04:00:27 +08:00
|
|
|
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
|
|
|
|
gimp_drawable_get_format (drawable));
|
2012-03-15 19:30:41 +08:00
|
|
|
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (
|
2018-12-02 15:36:17 +08:00
|
|
|
drawable_buffer,
|
|
|
|
&drawable_rect, GEGL_ABYSS_NONE,
|
2018-05-24 22:21:21 +08:00
|
|
|
buffer,
|
|
|
|
GEGL_RECTANGLE (0, 0, 0, 0));
|
2012-03-22 21:13:17 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_object_ref (buffer);
|
2004-04-01 22:51:58 +08:00
|
|
|
}
|
|
|
|
|
2018-12-02 15:36:17 +08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
|
|
|
|
|
|
|
gimp_image_undo_push_drawable (image,
|
2004-04-01 22:51:58 +08:00
|
|
|
undo_desc, drawable,
|
2012-03-22 21:25:45 +08:00
|
|
|
buffer, x, y);
|
2004-04-01 22:51:58 +08:00
|
|
|
|
2012-03-22 21:13:17 +08:00
|
|
|
g_object_unref (buffer);
|
2004-04-01 22:51:58 +08:00
|
|
|
}
|
|
|
|
|
2004-03-15 22:10:30 +08:00
|
|
|
static void
|
2006-04-07 17:21:18 +08:00
|
|
|
gimp_drawable_real_swap_pixels (GimpDrawable *drawable,
|
2012-03-22 21:13:17 +08:00
|
|
|
GeglBuffer *buffer,
|
2006-04-07 17:21:18 +08:00
|
|
|
gint x,
|
2012-03-22 21:25:45 +08:00
|
|
|
gint y)
|
2004-03-15 22:10:30 +08:00
|
|
|
{
|
2012-03-22 21:13:17 +08:00
|
|
|
GeglBuffer *tmp;
|
2012-03-22 21:25:45 +08:00
|
|
|
gint width = gegl_buffer_get_width (buffer);
|
|
|
|
gint height = gegl_buffer_get_height (buffer);
|
2004-03-15 22:10:30 +08:00
|
|
|
|
2019-07-31 01:25:54 +08:00
|
|
|
tmp = gimp_gegl_buffer_dup (buffer);
|
2004-03-15 22:10:30 +08:00
|
|
|
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
|
|
|
|
GEGL_RECTANGLE (x, y, width, height), GEGL_ABYSS_NONE,
|
|
|
|
buffer,
|
|
|
|
GEGL_RECTANGLE (0, 0, 0, 0));
|
|
|
|
gimp_gegl_buffer_copy (tmp,
|
|
|
|
GEGL_RECTANGLE (0, 0, width, height), GEGL_ABYSS_NONE,
|
|
|
|
gimp_drawable_get_buffer (drawable),
|
|
|
|
GEGL_RECTANGLE (x, y, 0, 0));
|
2004-03-15 22:10:30 +08:00
|
|
|
|
2012-03-22 21:13:17 +08:00
|
|
|
g_object_unref (tmp);
|
2004-03-15 22:10:30 +08:00
|
|
|
|
|
|
|
gimp_drawable_update (drawable, x, y, width, height);
|
|
|
|
}
|
|
|
|
|
2017-04-22 03:21:10 +08:00
|
|
|
static GeglNode *
|
|
|
|
gimp_drawable_real_get_source_node (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_warn_if_fail (drawable->private->buffer_source_node == NULL);
|
|
|
|
|
|
|
|
drawable->private->buffer_source_node =
|
|
|
|
gegl_node_new_child (NULL,
|
2017-12-05 04:49:43 +08:00
|
|
|
"operation", "gimp:buffer-source-validate",
|
2017-04-22 03:21:10 +08:00
|
|
|
"buffer", gimp_drawable_get_buffer (drawable),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
return g_object_ref (drawable->private->buffer_source_node);
|
|
|
|
}
|
|
|
|
|
2018-12-28 15:06:40 +08:00
|
|
|
static void
|
|
|
|
gimp_drawable_format_changed (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_signal_emit (drawable, gimp_drawable_signals[FORMAT_CHANGED], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_drawable_alpha_changed (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_signal_emit (drawable, gimp_drawable_signals[ALPHA_CHANGED], 0);
|
|
|
|
}
|
|
|
|
|
2004-03-15 22:10:30 +08:00
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
2011-02-01 19:47:24 +08:00
|
|
|
GimpDrawable *
|
|
|
|
gimp_drawable_new (GType type,
|
|
|
|
GimpImage *image,
|
|
|
|
const gchar *name,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
2012-03-22 03:21:11 +08:00
|
|
|
const Babl *format)
|
2011-02-01 19:47:24 +08:00
|
|
|
{
|
|
|
|
GimpDrawable *drawable;
|
2018-02-10 18:26:26 +08:00
|
|
|
GeglBuffer *buffer;
|
2011-02-01 19:47:24 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
|
|
|
g_return_val_if_fail (g_type_is_a (type, GIMP_TYPE_DRAWABLE), NULL);
|
|
|
|
g_return_val_if_fail (width > 0 && height > 0, NULL);
|
2012-03-22 03:21:11 +08:00
|
|
|
g_return_val_if_fail (format != NULL, NULL);
|
2011-02-01 19:47:24 +08:00
|
|
|
|
|
|
|
drawable = GIMP_DRAWABLE (gimp_item_new (type,
|
|
|
|
image, name,
|
|
|
|
offset_x, offset_y,
|
|
|
|
width, height));
|
|
|
|
|
2018-02-10 18:26:26 +08:00
|
|
|
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height), format);
|
|
|
|
|
|
|
|
gimp_drawable_set_buffer (drawable, FALSE, NULL, buffer);
|
|
|
|
g_object_unref (buffer);
|
2011-02-01 19:47:24 +08:00
|
|
|
|
2023-09-05 06:16:17 +08:00
|
|
|
gimp_drawable_enable_resize_undo (drawable);
|
2023-07-27 04:19:13 +08:00
|
|
|
|
2011-02-01 19:47:24 +08:00
|
|
|
return drawable;
|
|
|
|
}
|
|
|
|
|
2007-12-04 19:30:31 +08:00
|
|
|
gint64
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_estimate_memsize (GimpDrawable *drawable,
|
|
|
|
GimpComponentType component_type,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
2007-12-04 19:30:31 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), 0);
|
|
|
|
|
|
|
|
return GIMP_DRAWABLE_GET_CLASS (drawable)->estimate_memsize (drawable,
|
2014-06-15 05:12:22 +08:00
|
|
|
component_type,
|
2007-12-04 19:30:31 +08:00
|
|
|
width, height);
|
|
|
|
}
|
|
|
|
|
2001-07-08 06:49:01 +08:00
|
|
|
void
|
|
|
|
gimp_drawable_update (GimpDrawable *drawable,
|
2004-07-14 18:31:59 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
2001-07-08 06:49:01 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
if (width < 0)
|
|
|
|
{
|
|
|
|
GeglRectangle bounding_box;
|
|
|
|
|
|
|
|
bounding_box = gimp_drawable_get_bounding_box (drawable);
|
2017-01-13 09:14:40 +08:00
|
|
|
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
x = bounding_box.x;
|
|
|
|
width = bounding_box.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (height < 0)
|
|
|
|
{
|
|
|
|
GeglRectangle bounding_box;
|
|
|
|
|
|
|
|
bounding_box = gimp_drawable_get_bounding_box (drawable);
|
|
|
|
|
|
|
|
y = bounding_box.y;
|
|
|
|
height = bounding_box.height;
|
|
|
|
}
|
2017-01-13 09:14:40 +08:00
|
|
|
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
if (drawable->private->paint_count == 0)
|
|
|
|
{
|
|
|
|
g_signal_emit (drawable, gimp_drawable_signals[UPDATE], 0,
|
|
|
|
x, y, width, height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GeglRectangle rect;
|
|
|
|
|
|
|
|
if (gegl_rectangle_intersect (
|
|
|
|
&rect,
|
2019-07-31 01:27:11 +08:00
|
|
|
GEGL_RECTANGLE (x, y, width, height),
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
GEGL_RECTANGLE (0, 0,
|
|
|
|
gimp_item_get_width (GIMP_ITEM (drawable)),
|
|
|
|
gimp_item_get_height (GIMP_ITEM (drawable)))))
|
|
|
|
{
|
2019-07-31 01:27:11 +08:00
|
|
|
GeglRectangle aligned_rect;
|
|
|
|
|
|
|
|
gegl_rectangle_align_to_buffer (&aligned_rect, &rect,
|
|
|
|
gimp_drawable_get_buffer (drawable),
|
|
|
|
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
|
|
|
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
if (drawable->private->paint_copy_region)
|
|
|
|
{
|
|
|
|
cairo_region_union_rectangle (
|
|
|
|
drawable->private->paint_copy_region,
|
2019-07-31 01:27:11 +08:00
|
|
|
(const cairo_rectangle_int_t *) &aligned_rect);
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
drawable->private->paint_copy_region =
|
|
|
|
cairo_region_create_rectangle (
|
2019-07-31 01:27:11 +08:00
|
|
|
(const cairo_rectangle_int_t *) &aligned_rect);
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
}
|
|
|
|
|
2019-07-31 01:27:11 +08:00
|
|
|
gegl_rectangle_align (&aligned_rect, &rect,
|
|
|
|
GEGL_RECTANGLE (0, 0,
|
|
|
|
PAINT_UPDATE_CHUNK_WIDTH,
|
|
|
|
PAINT_UPDATE_CHUNK_HEIGHT),
|
|
|
|
GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
|
|
|
|
|
|
|
|
if (drawable->private->paint_update_region)
|
|
|
|
{
|
|
|
|
cairo_region_union_rectangle (
|
|
|
|
drawable->private->paint_update_region,
|
|
|
|
(const cairo_rectangle_int_t *) &aligned_rect);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
drawable->private->paint_update_region =
|
|
|
|
cairo_region_create_rectangle (
|
|
|
|
(const cairo_rectangle_int_t *) &aligned_rect);
|
|
|
|
}
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
}
|
|
|
|
}
|
2001-07-08 06:49:01 +08:00
|
|
|
}
|
|
|
|
|
app: add gimp_drawable_update_all()
Add a new GimpDrawable::update_all() virtual function, and a
corresponding gimp_drawable_update_all() function, which updates
the full contents of the drawable. Unlike calling
`gimp_drawable_update (drawable, 0, 0, -1, -1)`, which updates the
entire drawable area, gimp_drawable_update_all() only updates the
area that has actual content. While the default implentation does
simply update the entire drawable area, GimpGroupLayer overrides
this function to recursively update its child layers, rather than
the its entire area.
2019-06-10 15:42:07 +08:00
|
|
|
void
|
|
|
|
gimp_drawable_update_all (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
|
|
|
GIMP_DRAWABLE_GET_CLASS (drawable)->update_all (drawable);
|
|
|
|
}
|
|
|
|
|
2003-10-06 22:40:12 +08:00
|
|
|
void
|
|
|
|
gimp_drawable_invalidate_boundary (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
GimpDrawableClass *drawable_class;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
|
|
|
drawable_class = GIMP_DRAWABLE_GET_CLASS (drawable);
|
|
|
|
|
|
|
|
if (drawable_class->invalidate_boundary)
|
|
|
|
drawable_class->invalidate_boundary (drawable);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_active_components (GimpDrawable *drawable,
|
|
|
|
gboolean *active)
|
2003-10-06 22:40:12 +08:00
|
|
|
{
|
|
|
|
GimpDrawableClass *drawable_class;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
g_return_if_fail (active != NULL);
|
|
|
|
|
|
|
|
drawable_class = GIMP_DRAWABLE_GET_CLASS (drawable);
|
|
|
|
|
|
|
|
if (drawable_class->get_active_components)
|
|
|
|
drawable_class->get_active_components (drawable, active);
|
|
|
|
}
|
|
|
|
|
2012-04-26 05:23:31 +08:00
|
|
|
GimpComponentMask
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_active_mask (GimpDrawable *drawable)
|
2012-04-26 05:23:31 +08:00
|
|
|
{
|
2019-02-17 01:56:20 +08:00
|
|
|
GimpComponentMask mask;
|
2012-04-26 05:23:31 +08:00
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), 0);
|
|
|
|
|
2019-02-17 01:56:20 +08:00
|
|
|
mask = GIMP_DRAWABLE_GET_CLASS (drawable)->get_active_mask (drawable);
|
2012-04-26 05:23:31 +08:00
|
|
|
|
2019-02-17 01:56:20 +08:00
|
|
|
/* if the drawable doesn't have an alpha channel, the value of the mask's
|
|
|
|
* alpha-bit doesn't matter, however, we'd like to have a fully-clear or
|
|
|
|
* fully-set mask whenever possible, since it allows us to skip component
|
|
|
|
* masking altogether. we therefore set or clear the alpha bit, depending on
|
|
|
|
* the state of the other bits, so that it never gets in the way of a uniform
|
|
|
|
* mask.
|
|
|
|
*/
|
|
|
|
if (! gimp_drawable_has_alpha (drawable))
|
|
|
|
{
|
|
|
|
if (mask & ~GIMP_COMPONENT_MASK_ALPHA)
|
|
|
|
mask |= GIMP_COMPONENT_MASK_ALPHA;
|
|
|
|
else
|
|
|
|
mask &= ~GIMP_COMPONENT_MASK_ALPHA;
|
|
|
|
}
|
2012-04-26 05:23:31 +08:00
|
|
|
|
2019-02-17 01:56:20 +08:00
|
|
|
return mask;
|
2012-04-26 05:23:31 +08:00
|
|
|
}
|
|
|
|
|
2020-01-17 17:24:31 +08:00
|
|
|
gboolean
|
|
|
|
gimp_drawable_supports_alpha (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
|
|
|
|
return GIMP_DRAWABLE_GET_CLASS (drawable)->supports_alpha (drawable);
|
|
|
|
}
|
|
|
|
|
2009-09-12 03:23:35 +08:00
|
|
|
void
|
|
|
|
gimp_drawable_convert_type (GimpDrawable *drawable,
|
|
|
|
GimpImage *dest_image,
|
2009-09-14 01:24:19 +08:00
|
|
|
GimpImageBaseType new_base_type,
|
2012-04-25 18:09:45 +08:00
|
|
|
GimpPrecision new_precision,
|
2016-10-04 07:39:15 +08:00
|
|
|
gboolean new_has_alpha,
|
2018-08-06 04:19:17 +08:00
|
|
|
GimpColorProfile *src_profile,
|
2016-04-29 06:42:42 +08:00
|
|
|
GimpColorProfile *dest_profile,
|
2016-11-08 03:41:39 +08:00
|
|
|
GeglDitherMethod layer_dither_type,
|
|
|
|
GeglDitherMethod mask_dither_type,
|
2015-10-22 04:22:30 +08:00
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress)
|
2009-09-12 03:23:35 +08:00
|
|
|
{
|
2016-11-09 19:45:52 +08:00
|
|
|
const Babl *old_format;
|
2012-10-14 04:56:32 +08:00
|
|
|
const Babl *new_format;
|
2016-11-09 19:45:52 +08:00
|
|
|
gint old_bits;
|
|
|
|
gint new_bits;
|
2012-10-14 04:56:32 +08:00
|
|
|
|
2009-09-12 03:23:35 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2012-04-12 00:50:57 +08:00
|
|
|
g_return_if_fail (GIMP_IS_IMAGE (dest_image));
|
2012-04-25 18:09:45 +08:00
|
|
|
g_return_if_fail (new_base_type != gimp_drawable_get_base_type (drawable) ||
|
2015-08-16 21:47:43 +08:00
|
|
|
new_precision != gimp_drawable_get_precision (drawable) ||
|
2016-10-04 07:39:15 +08:00
|
|
|
new_has_alpha != gimp_drawable_has_alpha (drawable) ||
|
2016-04-29 06:42:42 +08:00
|
|
|
dest_profile);
|
2018-08-06 04:19:17 +08:00
|
|
|
g_return_if_fail (src_profile == NULL || GIMP_IS_COLOR_PROFILE (src_profile));
|
2016-04-29 06:42:42 +08:00
|
|
|
g_return_if_fail (dest_profile == NULL || GIMP_IS_COLOR_PROFILE (dest_profile));
|
2015-10-22 04:22:30 +08:00
|
|
|
g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
|
2009-09-12 03:23:35 +08:00
|
|
|
|
2009-09-14 01:24:19 +08:00
|
|
|
if (! gimp_item_is_attached (GIMP_ITEM (drawable)))
|
|
|
|
push_undo = FALSE;
|
|
|
|
|
2016-11-09 19:45:52 +08:00
|
|
|
old_format = gimp_drawable_get_format (drawable);
|
2012-10-14 04:56:32 +08:00
|
|
|
new_format = gimp_image_get_format (dest_image,
|
|
|
|
new_base_type,
|
|
|
|
new_precision,
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
new_has_alpha,
|
|
|
|
NULL /* handled by layer */);
|
2012-10-14 04:56:32 +08:00
|
|
|
|
2016-11-09 19:45:52 +08:00
|
|
|
old_bits = (babl_format_get_bytes_per_pixel (old_format) * 8 /
|
|
|
|
babl_format_get_n_components (old_format));
|
|
|
|
new_bits = (babl_format_get_bytes_per_pixel (new_format) * 8 /
|
|
|
|
babl_format_get_n_components (new_format));
|
|
|
|
|
|
|
|
if (old_bits <= new_bits || new_bits > 16)
|
|
|
|
{
|
|
|
|
/* don't dither if we are converting to a higher bit depth,
|
2016-12-25 02:39:32 +08:00
|
|
|
* or to more than 16 bits (gegl:dither only does
|
2016-11-09 19:45:52 +08:00
|
|
|
* 16 bits).
|
|
|
|
*/
|
|
|
|
layer_dither_type = GEGL_DITHER_NONE;
|
|
|
|
mask_dither_type = GEGL_DITHER_NONE;
|
|
|
|
}
|
|
|
|
|
2009-09-12 03:23:35 +08:00
|
|
|
GIMP_DRAWABLE_GET_CLASS (drawable)->convert_type (drawable, dest_image,
|
2012-10-14 04:56:32 +08:00
|
|
|
new_format,
|
2018-08-06 04:19:17 +08:00
|
|
|
src_profile,
|
2016-04-29 06:42:42 +08:00
|
|
|
dest_profile,
|
2012-10-14 03:46:56 +08:00
|
|
|
layer_dither_type,
|
|
|
|
mask_dither_type,
|
2015-10-22 04:22:30 +08:00
|
|
|
push_undo,
|
|
|
|
progress);
|
|
|
|
|
|
|
|
if (progress)
|
|
|
|
gimp_progress_set_value (progress, 1.0);
|
2009-09-12 03:23:35 +08:00
|
|
|
}
|
|
|
|
|
2012-03-23 01:40:40 +08:00
|
|
|
void
|
2017-02-02 07:38:25 +08:00
|
|
|
gimp_drawable_apply_buffer (GimpDrawable *drawable,
|
|
|
|
GeglBuffer *buffer,
|
|
|
|
const GeglRectangle *buffer_region,
|
|
|
|
gboolean push_undo,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
gdouble opacity,
|
|
|
|
GimpLayerMode mode,
|
2017-02-13 06:49:26 +08:00
|
|
|
GimpLayerColorSpace blend_space,
|
|
|
|
GimpLayerColorSpace composite_space,
|
|
|
|
GimpLayerCompositeMode composite_mode,
|
2017-02-02 07:38:25 +08:00
|
|
|
GeglBuffer *base_buffer,
|
|
|
|
gint base_x,
|
|
|
|
gint base_y)
|
2012-03-23 01:40:40 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
|
|
|
|
g_return_if_fail (GEGL_IS_BUFFER (buffer));
|
2012-03-23 06:45:11 +08:00
|
|
|
g_return_if_fail (buffer_region != NULL);
|
2012-03-23 07:12:13 +08:00
|
|
|
g_return_if_fail (base_buffer == NULL || GEGL_IS_BUFFER (base_buffer));
|
2003-10-06 22:40:12 +08:00
|
|
|
|
2012-03-23 06:45:11 +08:00
|
|
|
GIMP_DRAWABLE_GET_CLASS (drawable)->apply_buffer (drawable, buffer,
|
|
|
|
buffer_region,
|
2003-10-06 22:40:12 +08:00
|
|
|
push_undo, undo_desc,
|
2017-02-13 06:49:26 +08:00
|
|
|
opacity, mode,
|
|
|
|
blend_space,
|
|
|
|
composite_space,
|
|
|
|
composite_mode,
|
2012-03-23 07:12:13 +08:00
|
|
|
base_buffer,
|
2012-05-19 06:14:51 +08:00
|
|
|
base_x, base_y);
|
2003-10-06 22:40:12 +08:00
|
|
|
}
|
|
|
|
|
2012-03-15 09:42:59 +08:00
|
|
|
GeglBuffer *
|
2012-03-21 07:42:44 +08:00
|
|
|
gimp_drawable_get_buffer (GimpDrawable *drawable)
|
2012-03-15 09:42:59 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
if (drawable->private->paint_count == 0)
|
|
|
|
return GIMP_DRAWABLE_GET_CLASS (drawable)->get_buffer (drawable);
|
|
|
|
else
|
|
|
|
return drawable->private->paint_buffer;
|
2012-03-15 09:42:59 +08:00
|
|
|
}
|
|
|
|
|
2004-03-13 21:56:09 +08:00
|
|
|
void
|
2012-03-22 06:37:16 +08:00
|
|
|
gimp_drawable_set_buffer (GimpDrawable *drawable,
|
|
|
|
gboolean push_undo,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GeglBuffer *buffer)
|
2004-03-16 03:34:35 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2018-02-14 23:29:35 +08:00
|
|
|
g_return_if_fail (GEGL_IS_BUFFER (buffer));
|
2004-03-16 03:34:35 +08:00
|
|
|
|
2004-11-16 21:41:55 +08:00
|
|
|
if (! gimp_item_is_attached (GIMP_ITEM (drawable)))
|
|
|
|
push_undo = FALSE;
|
|
|
|
|
2019-08-02 02:41:47 +08:00
|
|
|
gimp_drawable_set_buffer_full (drawable, push_undo, undo_desc, buffer, NULL,
|
|
|
|
TRUE);
|
2004-03-16 03:34:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-08-02 02:41:47 +08:00
|
|
|
gimp_drawable_set_buffer_full (GimpDrawable *drawable,
|
|
|
|
gboolean push_undo,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GeglBuffer *buffer,
|
|
|
|
const GeglRectangle *bounds,
|
|
|
|
gboolean update)
|
2004-03-13 21:56:09 +08:00
|
|
|
{
|
2019-08-02 02:41:47 +08:00
|
|
|
GimpItem *item;
|
|
|
|
GeglRectangle curr_bounds;
|
2004-03-16 04:05:31 +08:00
|
|
|
|
2004-03-13 21:56:09 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2018-02-14 23:29:35 +08:00
|
|
|
g_return_if_fail (GEGL_IS_BUFFER (buffer));
|
2004-03-13 21:56:09 +08:00
|
|
|
|
2011-05-02 05:23:19 +08:00
|
|
|
item = GIMP_ITEM (drawable);
|
2004-04-13 21:54:54 +08:00
|
|
|
|
2004-11-16 21:41:55 +08:00
|
|
|
if (! gimp_item_is_attached (GIMP_ITEM (drawable)))
|
|
|
|
push_undo = FALSE;
|
|
|
|
|
2019-08-02 02:41:47 +08:00
|
|
|
if (! bounds)
|
2004-03-16 04:05:31 +08:00
|
|
|
{
|
2019-08-02 02:41:47 +08:00
|
|
|
gimp_item_get_offset (GIMP_ITEM (drawable),
|
|
|
|
&curr_bounds.x, &curr_bounds.y);
|
|
|
|
|
|
|
|
curr_bounds.width = 0;
|
|
|
|
curr_bounds.height = 0;
|
|
|
|
|
|
|
|
bounds = &curr_bounds;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (update && gimp_drawable_get_buffer (drawable))
|
|
|
|
{
|
|
|
|
GeglBuffer *old_buffer = gimp_drawable_get_buffer (drawable);
|
|
|
|
GeglRectangle old_extent;
|
|
|
|
GeglRectangle new_extent;
|
|
|
|
|
|
|
|
old_extent = *gegl_buffer_get_extent (old_buffer);
|
|
|
|
old_extent.x += gimp_item_get_offset_x (item);
|
|
|
|
old_extent.y += gimp_item_get_offset_x (item);
|
|
|
|
|
|
|
|
new_extent = *gegl_buffer_get_extent (buffer);
|
|
|
|
new_extent.x += bounds->x;
|
|
|
|
new_extent.y += bounds->y;
|
|
|
|
|
|
|
|
if (! gegl_rectangle_equal (&old_extent, &new_extent))
|
|
|
|
gimp_drawable_update (drawable, 0, 0, -1, -1);
|
2004-03-16 04:05:31 +08:00
|
|
|
}
|
|
|
|
|
2009-08-26 19:20:18 +08:00
|
|
|
g_object_freeze_notify (G_OBJECT (drawable));
|
|
|
|
|
2012-03-22 06:37:16 +08:00
|
|
|
GIMP_DRAWABLE_GET_CLASS (drawable)->set_buffer (drawable,
|
|
|
|
push_undo, undo_desc,
|
2019-08-02 02:41:47 +08:00
|
|
|
buffer, bounds);
|
2004-03-16 04:05:31 +08:00
|
|
|
|
2009-08-26 19:20:18 +08:00
|
|
|
g_object_thaw_notify (G_OBJECT (drawable));
|
|
|
|
|
2018-08-04 00:58:03 +08:00
|
|
|
if (update)
|
|
|
|
gimp_drawable_update (drawable, 0, 0, -1, -1);
|
2004-03-13 21:56:09 +08:00
|
|
|
}
|
|
|
|
|
2018-02-14 02:09:07 +08:00
|
|
|
void
|
|
|
|
gimp_drawable_steal_buffer (GimpDrawable *drawable,
|
|
|
|
GimpDrawable *src_drawable)
|
|
|
|
{
|
|
|
|
GeglBuffer *buffer;
|
2018-02-14 23:29:35 +08:00
|
|
|
GeglBuffer *replacement_buffer;
|
2018-02-14 02:09:07 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (src_drawable));
|
|
|
|
|
|
|
|
buffer = gimp_drawable_get_buffer (src_drawable);
|
|
|
|
|
2018-02-14 23:29:35 +08:00
|
|
|
g_return_if_fail (buffer != NULL);
|
|
|
|
|
|
|
|
g_object_ref (buffer);
|
2018-02-14 02:09:07 +08:00
|
|
|
|
2018-02-14 23:29:35 +08:00
|
|
|
replacement_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, 1, 1),
|
|
|
|
gegl_buffer_get_format (buffer));
|
|
|
|
|
|
|
|
gimp_drawable_set_buffer (src_drawable, FALSE, NULL, replacement_buffer);
|
2018-02-14 02:09:07 +08:00
|
|
|
gimp_drawable_set_buffer (drawable, FALSE, NULL, buffer);
|
|
|
|
|
2018-02-14 23:29:35 +08:00
|
|
|
g_object_unref (replacement_buffer);
|
|
|
|
g_object_unref (buffer);
|
2018-02-14 02:09:07 +08:00
|
|
|
}
|
|
|
|
|
2018-07-24 18:20:17 +08:00
|
|
|
void
|
|
|
|
gimp_drawable_set_format (GimpDrawable *drawable,
|
|
|
|
const Babl *format,
|
|
|
|
gboolean copy_buffer,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
GimpItem *item;
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
g_return_if_fail (format != NULL);
|
|
|
|
g_return_if_fail (format != gimp_drawable_get_format (drawable));
|
|
|
|
g_return_if_fail (gimp_babl_format_get_base_type (format) ==
|
|
|
|
gimp_drawable_get_base_type (drawable));
|
|
|
|
g_return_if_fail (gimp_babl_format_get_component_type (format) ==
|
|
|
|
gimp_drawable_get_component_type (drawable));
|
|
|
|
g_return_if_fail (babl_format_has_alpha (format) ==
|
|
|
|
gimp_drawable_has_alpha (drawable));
|
|
|
|
g_return_if_fail (push_undo == FALSE || copy_buffer == TRUE);
|
|
|
|
|
|
|
|
item = GIMP_ITEM (drawable);
|
|
|
|
|
|
|
|
if (! gimp_item_is_attached (item))
|
|
|
|
push_undo = FALSE;
|
|
|
|
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_push_drawable_format (gimp_item_get_image (item),
|
|
|
|
NULL, drawable);
|
|
|
|
|
|
|
|
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
|
|
|
|
gimp_item_get_width (item),
|
|
|
|
gimp_item_get_height (item)),
|
|
|
|
format);
|
|
|
|
|
|
|
|
if (copy_buffer)
|
|
|
|
{
|
|
|
|
gegl_buffer_set_format (buffer, gimp_drawable_get_format (drawable));
|
|
|
|
|
|
|
|
gimp_gegl_buffer_copy (gimp_drawable_get_buffer (drawable),
|
|
|
|
NULL, GEGL_ABYSS_NONE,
|
|
|
|
buffer, NULL);
|
|
|
|
|
|
|
|
gegl_buffer_set_format (buffer, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_drawable_set_buffer (drawable, FALSE, NULL, buffer);
|
|
|
|
g_object_unref (buffer);
|
|
|
|
}
|
|
|
|
|
2008-10-10 04:44:23 +08:00
|
|
|
GeglNode *
|
|
|
|
gimp_drawable_get_source_node (GimpDrawable *drawable)
|
|
|
|
{
|
2018-12-28 15:19:02 +08:00
|
|
|
GeglNode *input;
|
|
|
|
GeglNode *source;
|
|
|
|
GeglNode *filter;
|
|
|
|
GeglNode *output;
|
2013-04-12 01:06:23 +08:00
|
|
|
|
2008-10-10 04:44:23 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
|
2009-02-04 07:57:11 +08:00
|
|
|
if (drawable->private->source_node)
|
|
|
|
return drawable->private->source_node;
|
2008-10-10 04:44:23 +08:00
|
|
|
|
2009-02-04 07:57:11 +08:00
|
|
|
drawable->private->source_node = gegl_node_new ();
|
2009-01-27 06:05:07 +08:00
|
|
|
|
2017-04-22 03:38:57 +08:00
|
|
|
input = gegl_node_get_input_proxy (drawable->private->source_node, "input");
|
|
|
|
|
2017-04-22 03:21:10 +08:00
|
|
|
source = GIMP_DRAWABLE_GET_CLASS (drawable)->get_source_node (drawable);
|
|
|
|
|
|
|
|
gegl_node_add_child (drawable->private->source_node, source);
|
|
|
|
|
|
|
|
g_object_unref (source);
|
2009-01-27 06:05:07 +08:00
|
|
|
|
2017-04-22 03:38:57 +08:00
|
|
|
if (gegl_node_has_pad (source, "input"))
|
|
|
|
{
|
2023-06-13 23:05:02 +08:00
|
|
|
gegl_node_link (input, source);
|
2017-04-22 03:38:57 +08:00
|
|
|
}
|
|
|
|
|
2013-04-12 01:06:23 +08:00
|
|
|
filter = gimp_filter_stack_get_graph (GIMP_FILTER_STACK (drawable->private->filter_stack));
|
|
|
|
|
|
|
|
gegl_node_add_child (drawable->private->source_node, filter);
|
|
|
|
|
2023-06-13 23:05:02 +08:00
|
|
|
gegl_node_link (source, filter);
|
2013-04-12 01:06:23 +08:00
|
|
|
|
|
|
|
output = gegl_node_get_output_proxy (drawable->private->source_node, "output");
|
|
|
|
|
2023-06-13 23:05:02 +08:00
|
|
|
gegl_node_link (filter, output);
|
2013-04-12 01:06:23 +08:00
|
|
|
|
2016-05-19 23:38:55 +08:00
|
|
|
if (gimp_drawable_get_floating_sel (drawable))
|
|
|
|
_gimp_drawable_add_floating_sel_filter (drawable);
|
2008-10-10 04:44:23 +08:00
|
|
|
|
2009-02-04 07:57:11 +08:00
|
|
|
return drawable->private->source_node;
|
2008-10-10 04:44:23 +08:00
|
|
|
}
|
|
|
|
|
2008-10-15 02:32:07 +08:00
|
|
|
GeglNode *
|
|
|
|
gimp_drawable_get_mode_node (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
|
2009-02-04 07:57:11 +08:00
|
|
|
if (! drawable->private->mode_node)
|
2013-04-11 08:54:42 +08:00
|
|
|
gimp_filter_get_node (GIMP_FILTER (drawable));
|
2008-10-11 03:36:17 +08:00
|
|
|
|
2009-02-04 07:57:11 +08:00
|
|
|
return drawable->private->mode_node;
|
2008-10-11 03:36:17 +08:00
|
|
|
}
|
|
|
|
|
app: maintain drawable bounding box separately from its logical boundary
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
2019-08-02 02:52:40 +08:00
|
|
|
GeglRectangle
|
|
|
|
gimp_drawable_get_bounding_box (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable),
|
|
|
|
*GEGL_RECTANGLE (0, 0, 0, 0));
|
|
|
|
|
|
|
|
if (gegl_rectangle_is_empty (&drawable->private->bounding_box))
|
|
|
|
gimp_drawable_update_bounding_box (drawable);
|
|
|
|
|
|
|
|
return drawable->private->bounding_box;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_drawable_update_bounding_box (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
GeglRectangle bounding_box;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
|
|
|
|
bounding_box =
|
|
|
|
GIMP_DRAWABLE_GET_CLASS (drawable)->get_bounding_box (drawable);
|
|
|
|
|
|
|
|
if (! gegl_rectangle_equal (&bounding_box, &drawable->private->bounding_box))
|
|
|
|
{
|
|
|
|
GeglRectangle old_bounding_box = drawable->private->bounding_box;
|
|
|
|
GeglRectangle diff_rects[4];
|
|
|
|
gint n_diff_rects;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
n_diff_rects = gegl_rectangle_subtract (diff_rects,
|
|
|
|
&old_bounding_box,
|
|
|
|
&bounding_box);
|
|
|
|
|
|
|
|
for (i = 0; i < n_diff_rects; i++)
|
|
|
|
{
|
|
|
|
gimp_drawable_update (drawable,
|
|
|
|
diff_rects[i].x,
|
|
|
|
diff_rects[i].y,
|
|
|
|
diff_rects[i].width,
|
|
|
|
diff_rects[i].height);
|
|
|
|
}
|
|
|
|
|
|
|
|
drawable->private->bounding_box = bounding_box;
|
|
|
|
|
|
|
|
g_signal_emit (drawable, gimp_drawable_signals[BOUNDING_BOX_CHANGED], 0);
|
|
|
|
|
|
|
|
n_diff_rects = gegl_rectangle_subtract (diff_rects,
|
|
|
|
&bounding_box,
|
|
|
|
&old_bounding_box);
|
|
|
|
|
|
|
|
for (i = 0; i < n_diff_rects; i++)
|
|
|
|
{
|
|
|
|
gimp_drawable_update (drawable,
|
|
|
|
diff_rects[i].x,
|
|
|
|
diff_rects[i].y,
|
|
|
|
diff_rects[i].width,
|
|
|
|
diff_rects[i].height);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2004-03-15 22:10:30 +08:00
|
|
|
void
|
|
|
|
gimp_drawable_swap_pixels (GimpDrawable *drawable,
|
2012-03-22 21:13:17 +08:00
|
|
|
GeglBuffer *buffer,
|
2004-03-15 22:10:30 +08:00
|
|
|
gint x,
|
2012-03-22 21:25:45 +08:00
|
|
|
gint y)
|
2004-03-15 22:10:30 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2012-03-22 21:13:17 +08:00
|
|
|
g_return_if_fail (GEGL_IS_BUFFER (buffer));
|
2004-03-15 22:10:30 +08:00
|
|
|
|
2012-03-22 21:25:45 +08:00
|
|
|
GIMP_DRAWABLE_GET_CLASS (drawable)->swap_pixels (drawable, buffer, x, y);
|
2004-03-15 22:10:30 +08:00
|
|
|
}
|
|
|
|
|
2001-07-08 06:49:01 +08:00
|
|
|
void
|
2003-02-14 22:14:29 +08:00
|
|
|
gimp_drawable_push_undo (GimpDrawable *drawable,
|
|
|
|
const gchar *undo_desc,
|
2012-03-22 21:13:17 +08:00
|
|
|
GeglBuffer *buffer,
|
2009-06-17 04:59:07 +08:00
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
2012-03-22 21:13:17 +08:00
|
|
|
gint height)
|
2001-07-08 06:49:01 +08:00
|
|
|
{
|
2004-03-15 22:10:30 +08:00
|
|
|
GimpItem *item;
|
|
|
|
|
2001-07-08 06:49:01 +08:00
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
2012-03-22 21:13:17 +08:00
|
|
|
g_return_if_fail (buffer == NULL || GEGL_IS_BUFFER (buffer));
|
2004-03-15 22:10:30 +08:00
|
|
|
|
|
|
|
item = GIMP_ITEM (drawable);
|
|
|
|
|
2004-11-16 21:41:55 +08:00
|
|
|
g_return_if_fail (gimp_item_is_attached (item));
|
2004-03-15 22:10:30 +08:00
|
|
|
|
2012-03-22 21:13:17 +08:00
|
|
|
if (! buffer &&
|
|
|
|
! gimp_rectangle_intersect (x, y,
|
2009-06-17 04:59:07 +08:00
|
|
|
width, height,
|
2004-03-15 22:10:30 +08:00
|
|
|
0, 0,
|
2008-11-03 08:09:01 +08:00
|
|
|
gimp_item_get_width (item),
|
|
|
|
gimp_item_get_height (item),
|
2004-03-15 22:10:30 +08:00
|
|
|
&x, &y, &width, &height))
|
|
|
|
{
|
2004-05-12 16:13:33 +08:00
|
|
|
g_warning ("%s: tried to push empty region", G_STRFUNC);
|
2004-03-15 22:10:30 +08:00
|
|
|
return;
|
|
|
|
}
|
2001-07-08 06:49:01 +08:00
|
|
|
|
2004-04-01 22:51:58 +08:00
|
|
|
GIMP_DRAWABLE_GET_CLASS (drawable)->push_undo (drawable, undo_desc,
|
2012-03-22 21:13:17 +08:00
|
|
|
buffer,
|
2004-04-01 22:51:58 +08:00
|
|
|
x, y, width, height);
|
2001-07-08 06:49:01 +08:00
|
|
|
}
|
|
|
|
|
2023-07-27 04:19:13 +08:00
|
|
|
void
|
2023-09-05 06:16:17 +08:00
|
|
|
gimp_drawable_disable_resize_undo (GimpDrawable *drawable)
|
2023-07-27 04:19:13 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
2023-09-05 06:16:17 +08:00
|
|
|
drawable->private->push_resize_undo = FALSE;
|
2023-07-27 04:19:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-09-05 06:16:17 +08:00
|
|
|
gimp_drawable_enable_resize_undo (GimpDrawable *drawable)
|
2023-07-27 04:19:13 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
2023-09-05 06:16:17 +08:00
|
|
|
drawable->private->push_resize_undo = TRUE;
|
2023-07-27 04:19:13 +08:00
|
|
|
}
|
|
|
|
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
const Babl *
|
|
|
|
gimp_drawable_get_space (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
|
|
|
|
return babl_format_get_space (gimp_drawable_get_format (drawable));
|
|
|
|
}
|
|
|
|
|
2012-03-16 07:01:34 +08:00
|
|
|
const Babl *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_format (GimpDrawable *drawable)
|
2012-03-16 07:01:34 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
|
2012-03-30 05:19:27 +08:00
|
|
|
return gegl_buffer_get_format (drawable->private->buffer);
|
2012-03-16 07:01:34 +08:00
|
|
|
}
|
|
|
|
|
2012-03-18 04:21:36 +08:00
|
|
|
const Babl *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_format_with_alpha (GimpDrawable *drawable)
|
2012-03-18 04:21:36 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
|
2012-04-12 00:40:30 +08:00
|
|
|
return gimp_image_get_format (gimp_item_get_image (GIMP_ITEM (drawable)),
|
|
|
|
gimp_drawable_get_base_type (drawable),
|
2012-05-08 03:46:47 +08:00
|
|
|
gimp_drawable_get_precision (drawable),
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
TRUE,
|
|
|
|
gimp_drawable_get_space (drawable));
|
2012-03-18 04:21:36 +08:00
|
|
|
}
|
|
|
|
|
2012-03-18 23:24:29 +08:00
|
|
|
const Babl *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_format_without_alpha (GimpDrawable *drawable)
|
2012-03-18 23:24:29 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
|
2012-04-12 00:40:30 +08:00
|
|
|
return gimp_image_get_format (gimp_item_get_image (GIMP_ITEM (drawable)),
|
|
|
|
gimp_drawable_get_base_type (drawable),
|
2012-05-08 03:46:47 +08:00
|
|
|
gimp_drawable_get_precision (drawable),
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
FALSE,
|
|
|
|
gimp_drawable_get_space (drawable));
|
2012-03-18 23:24:29 +08:00
|
|
|
}
|
|
|
|
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
GimpTRCType
|
|
|
|
gimp_drawable_get_trc (GimpDrawable *drawable)
|
2013-04-27 14:41:06 +08:00
|
|
|
{
|
2013-05-01 06:05:53 +08:00
|
|
|
const Babl *format;
|
|
|
|
|
2013-04-27 14:41:06 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
|
2013-05-01 06:05:53 +08:00
|
|
|
format = gegl_buffer_get_format (drawable->private->buffer);
|
|
|
|
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
|
|
|
return gimp_babl_format_get_trc (format);
|
2013-04-27 14:41:06 +08:00
|
|
|
}
|
|
|
|
|
1999-08-22 19:45:31 +08:00
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_has_alpha (GimpDrawable *drawable)
|
1999-08-22 19:45:31 +08:00
|
|
|
{
|
2012-03-30 05:19:27 +08:00
|
|
|
const Babl *format;
|
|
|
|
|
2000-02-17 19:44:27 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
|
2012-03-30 05:19:27 +08:00
|
|
|
format = gegl_buffer_get_format (drawable->private->buffer);
|
|
|
|
|
|
|
|
return babl_format_has_alpha (format);
|
1999-08-22 19:45:31 +08:00
|
|
|
}
|
1998-10-14 10:54:02 +08:00
|
|
|
|
2012-04-07 07:51:08 +08:00
|
|
|
GimpImageBaseType
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_base_type (GimpDrawable *drawable)
|
2012-04-07 07:34:44 +08:00
|
|
|
{
|
|
|
|
const Babl *format;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);
|
|
|
|
|
|
|
|
format = gegl_buffer_get_format (drawable->private->buffer);
|
|
|
|
|
2012-04-07 08:27:58 +08:00
|
|
|
return gimp_babl_format_get_base_type (format);
|
2012-04-07 07:34:44 +08:00
|
|
|
}
|
|
|
|
|
2013-06-23 22:51:24 +08:00
|
|
|
GimpComponentType
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_component_type (GimpDrawable *drawable)
|
2013-06-23 22:51:24 +08:00
|
|
|
{
|
|
|
|
const Babl *format;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);
|
|
|
|
|
|
|
|
format = gegl_buffer_get_format (drawable->private->buffer);
|
|
|
|
|
|
|
|
return gimp_babl_format_get_component_type (format);
|
|
|
|
}
|
|
|
|
|
2012-04-22 23:31:32 +08:00
|
|
|
GimpPrecision
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_precision (GimpDrawable *drawable)
|
2012-04-22 23:31:32 +08:00
|
|
|
{
|
|
|
|
const Babl *format;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);
|
|
|
|
|
|
|
|
format = gegl_buffer_get_format (drawable->private->buffer);
|
|
|
|
|
|
|
|
return gimp_babl_format_get_precision (format);
|
|
|
|
}
|
|
|
|
|
2001-12-13 07:48:18 +08:00
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_is_rgb (GimpDrawable *drawable)
|
2001-12-13 07:48:18 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
|
2012-04-07 08:27:58 +08:00
|
|
|
return (gimp_drawable_get_base_type (drawable) == GIMP_RGB);
|
2001-12-13 07:48:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_is_gray (GimpDrawable *drawable)
|
2001-12-13 07:48:18 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
|
2012-04-07 08:27:58 +08:00
|
|
|
return (gimp_drawable_get_base_type (drawable) == GIMP_GRAY);
|
2001-12-13 07:48:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_is_indexed (GimpDrawable *drawable)
|
2001-12-13 07:48:18 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
|
2012-04-07 08:27:58 +08:00
|
|
|
return (gimp_drawable_get_base_type (drawable) == GIMP_INDEXED);
|
2001-12-13 07:48:18 +08:00
|
|
|
}
|
|
|
|
|
2014-06-02 08:31:42 +08:00
|
|
|
const Babl *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_component_format (GimpDrawable *drawable,
|
|
|
|
GimpChannelType channel)
|
2014-06-02 08:31:42 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
|
|
|
|
|
|
switch (channel)
|
|
|
|
{
|
2017-01-10 02:40:30 +08:00
|
|
|
case GIMP_CHANNEL_RED:
|
2014-06-02 08:31:42 +08:00
|
|
|
return gimp_babl_component_format (GIMP_RGB,
|
|
|
|
gimp_drawable_get_precision (drawable),
|
|
|
|
RED);
|
|
|
|
|
2017-01-10 02:40:30 +08:00
|
|
|
case GIMP_CHANNEL_GREEN:
|
2014-06-02 08:31:42 +08:00
|
|
|
return gimp_babl_component_format (GIMP_RGB,
|
|
|
|
gimp_drawable_get_precision (drawable),
|
|
|
|
GREEN);
|
|
|
|
|
2017-01-10 02:40:30 +08:00
|
|
|
case GIMP_CHANNEL_BLUE:
|
2014-06-02 08:31:42 +08:00
|
|
|
return gimp_babl_component_format (GIMP_RGB,
|
|
|
|
gimp_drawable_get_precision (drawable),
|
|
|
|
BLUE);
|
|
|
|
|
2017-01-10 02:40:30 +08:00
|
|
|
case GIMP_CHANNEL_ALPHA:
|
2014-06-02 08:31:42 +08:00
|
|
|
return gimp_babl_component_format (GIMP_RGB,
|
|
|
|
gimp_drawable_get_precision (drawable),
|
|
|
|
ALPHA);
|
|
|
|
|
2017-01-10 02:40:30 +08:00
|
|
|
case GIMP_CHANNEL_GRAY:
|
2014-06-02 08:31:42 +08:00
|
|
|
return gimp_babl_component_format (GIMP_GRAY,
|
|
|
|
gimp_drawable_get_precision (drawable),
|
|
|
|
GRAY);
|
|
|
|
|
2017-01-10 02:40:30 +08:00
|
|
|
case GIMP_CHANNEL_INDEXED:
|
2014-06-02 08:31:42 +08:00
|
|
|
return babl_format ("Y u8"); /* will extract grayscale, the best
|
|
|
|
* we can do here */
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_component_index (GimpDrawable *drawable,
|
|
|
|
GimpChannelType channel)
|
2014-06-02 08:31:42 +08:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);
|
|
|
|
|
|
|
|
switch (channel)
|
|
|
|
{
|
2017-01-10 02:40:30 +08:00
|
|
|
case GIMP_CHANNEL_RED: return RED;
|
|
|
|
case GIMP_CHANNEL_GREEN: return GREEN;
|
|
|
|
case GIMP_CHANNEL_BLUE: return BLUE;
|
|
|
|
case GIMP_CHANNEL_GRAY: return GRAY;
|
|
|
|
case GIMP_CHANNEL_INDEXED: return INDEXED;
|
|
|
|
case GIMP_CHANNEL_ALPHA:
|
2014-06-02 08:31:42 +08:00
|
|
|
switch (gimp_drawable_get_base_type (drawable))
|
|
|
|
{
|
|
|
|
case GIMP_RGB: return ALPHA;
|
|
|
|
case GIMP_GRAY: return ALPHA_G;
|
|
|
|
case GIMP_INDEXED: return ALPHA_I;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-11-08 17:50:32 +08:00
|
|
|
guchar *
|
2016-05-20 05:51:44 +08:00
|
|
|
gimp_drawable_get_colormap (GimpDrawable *drawable)
|
2004-04-13 21:54:54 +08:00
|
|
|
{
|
2006-03-29 01:08:36 +08:00
|
|
|
GimpImage *image;
|
2004-04-13 21:54:54 +08:00
|
|
|
|
2011-09-24 01:31:50 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
2004-04-13 21:54:54 +08:00
|
|
|
|
2006-03-29 01:08:36 +08:00
|
|
|
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
2004-04-13 21:54:54 +08:00
|
|
|
|
2011-09-24 01:31:50 +08:00
|
|
|
return image ? gimp_image_get_colormap (image) : NULL;
|
2004-04-13 21:54:54 +08:00
|
|
|
}
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
|
|
|
|
void
|
|
|
|
gimp_drawable_start_paint (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
|
|
|
|
|
|
if (drawable->private->paint_count == 0)
|
|
|
|
{
|
|
|
|
GeglBuffer *buffer = gimp_drawable_get_buffer (drawable);
|
|
|
|
|
|
|
|
g_return_if_fail (buffer != NULL);
|
|
|
|
g_return_if_fail (drawable->private->paint_buffer == NULL);
|
|
|
|
g_return_if_fail (drawable->private->paint_copy_region == NULL);
|
|
|
|
g_return_if_fail (drawable->private->paint_update_region == NULL);
|
|
|
|
|
2019-07-31 01:25:54 +08:00
|
|
|
drawable->private->paint_buffer = gimp_gegl_buffer_dup (buffer);
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
drawable->private->paint_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_drawable_end_paint (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
gboolean result = FALSE;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
g_return_val_if_fail (drawable->private->paint_count > 0, FALSE);
|
|
|
|
|
|
|
|
if (drawable->private->paint_count == 1)
|
|
|
|
{
|
|
|
|
result = gimp_drawable_flush_paint (drawable);
|
|
|
|
|
|
|
|
g_clear_object (&drawable->private->paint_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
drawable->private->paint_count--;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_drawable_flush_paint (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
g_return_val_if_fail (drawable->private->paint_count > 0, FALSE);
|
|
|
|
|
|
|
|
if (drawable->private->paint_copy_region)
|
|
|
|
{
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
gint n_rects;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
buffer = GIMP_DRAWABLE_GET_CLASS (drawable)->get_buffer (drawable);
|
|
|
|
|
|
|
|
g_return_val_if_fail (buffer != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (drawable->private->paint_buffer != NULL, FALSE);
|
|
|
|
|
|
|
|
n_rects = cairo_region_num_rectangles (
|
|
|
|
drawable->private->paint_copy_region);
|
|
|
|
|
|
|
|
for (i = 0; i < n_rects; i++)
|
|
|
|
{
|
|
|
|
GeglRectangle rect;
|
|
|
|
|
|
|
|
cairo_region_get_rectangle (drawable->private->paint_copy_region,
|
|
|
|
i, (cairo_rectangle_int_t *) &rect);
|
|
|
|
|
2018-05-24 22:21:21 +08:00
|
|
|
gimp_gegl_buffer_copy (
|
app: add gimp_drawable_{start,end,flush}_paint()
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
2018-04-08 21:21:46 +08:00
|
|
|
drawable->private->paint_buffer, &rect, GEGL_ABYSS_NONE,
|
|
|
|
buffer, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_clear_pointer (&drawable->private->paint_copy_region,
|
|
|
|
cairo_region_destroy);
|
|
|
|
|
|
|
|
n_rects = cairo_region_num_rectangles (
|
|
|
|
drawable->private->paint_update_region);
|
|
|
|
|
|
|
|
for (i = 0; i < n_rects; i++)
|
|
|
|
{
|
|
|
|
GeglRectangle rect;
|
|
|
|
|
|
|
|
cairo_region_get_rectangle (drawable->private->paint_update_region,
|
|
|
|
i, (cairo_rectangle_int_t *) &rect);
|
|
|
|
|
|
|
|
g_signal_emit (drawable, gimp_drawable_signals[UPDATE], 0,
|
|
|
|
rect.x, rect.y, rect.width, rect.height);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_clear_pointer (&drawable->private->paint_update_region,
|
|
|
|
cairo_region_destroy);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
2018-04-10 02:25:57 +08:00
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_drawable_is_painting (GimpDrawable *drawable)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
|
|
|
|
|
|
|
return drawable->private->paint_count > 0;
|
|
|
|
}
|