app: make replacing a drawable's format use almost no undo memory

Add gimp_drawable_set_format() as low-level part of
gimp_layer_fix_format_space(), and add a special undo type for it that
only remembers the format and not the entire drawable buffer, because
all pixels stay the same.
This commit is contained in:
Michael Natterer 2018-07-24 12:20:17 +02:00
parent a76553fb62
commit 248199e997
10 changed files with 290 additions and 21 deletions

View File

@ -206,6 +206,8 @@ libappcore_a_sources = \
gimpdrawablefilter.h \ gimpdrawablefilter.h \
gimpdrawablemodundo.c \ gimpdrawablemodundo.c \
gimpdrawablemodundo.h \ gimpdrawablemodundo.h \
gimpdrawablepropundo.c \
gimpdrawablepropundo.h \
gimpdrawablestack.c \ gimpdrawablestack.c \
gimpdrawablestack.h \ gimpdrawablestack.h \
gimpdrawableundo.c \ gimpdrawableundo.c \

View File

@ -1080,6 +1080,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_SAMPLE_POINT, "GIMP_UNDO_SAMPLE_POINT", "sample-point" }, { GIMP_UNDO_SAMPLE_POINT, "GIMP_UNDO_SAMPLE_POINT", "sample-point" },
{ GIMP_UNDO_DRAWABLE, "GIMP_UNDO_DRAWABLE", "drawable" }, { GIMP_UNDO_DRAWABLE, "GIMP_UNDO_DRAWABLE", "drawable" },
{ GIMP_UNDO_DRAWABLE_MOD, "GIMP_UNDO_DRAWABLE_MOD", "drawable-mod" }, { GIMP_UNDO_DRAWABLE_MOD, "GIMP_UNDO_DRAWABLE_MOD", "drawable-mod" },
{ GIMP_UNDO_DRAWABLE_FORMAT, "GIMP_UNDO_DRAWABLE_FORMAT", "drawable-format" },
{ GIMP_UNDO_MASK, "GIMP_UNDO_MASK", "mask" }, { GIMP_UNDO_MASK, "GIMP_UNDO_MASK", "mask" },
{ GIMP_UNDO_ITEM_REORDER, "GIMP_UNDO_ITEM_REORDER", "item-reorder" }, { GIMP_UNDO_ITEM_REORDER, "GIMP_UNDO_ITEM_REORDER", "item-reorder" },
{ GIMP_UNDO_ITEM_RENAME, "GIMP_UNDO_ITEM_RENAME", "item-rename" }, { GIMP_UNDO_ITEM_RENAME, "GIMP_UNDO_ITEM_RENAME", "item-rename" },
@ -1178,6 +1179,7 @@ gimp_undo_type_get_type (void)
{ GIMP_UNDO_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL }, { GIMP_UNDO_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL },
{ GIMP_UNDO_DRAWABLE, NC_("undo-type", "Layer/Channel"), NULL }, { GIMP_UNDO_DRAWABLE, NC_("undo-type", "Layer/Channel"), NULL },
{ GIMP_UNDO_DRAWABLE_MOD, NC_("undo-type", "Layer/Channel modification"), NULL }, { GIMP_UNDO_DRAWABLE_MOD, NC_("undo-type", "Layer/Channel modification"), NULL },
{ GIMP_UNDO_DRAWABLE_FORMAT, NC_("undo-type", "Layer/Channel format"), NULL },
{ GIMP_UNDO_MASK, NC_("undo-type", "Selection mask"), NULL }, { GIMP_UNDO_MASK, NC_("undo-type", "Selection mask"), NULL },
{ GIMP_UNDO_ITEM_REORDER, NC_("undo-type", "Reorder item"), NULL }, { GIMP_UNDO_ITEM_REORDER, NC_("undo-type", "Reorder item"), NULL },
{ GIMP_UNDO_ITEM_RENAME, NC_("undo-type", "Rename item"), NULL }, { GIMP_UNDO_ITEM_RENAME, NC_("undo-type", "Rename item"), NULL },

View File

@ -515,6 +515,7 @@ typedef enum /*< pdb-skip >*/
GIMP_UNDO_SAMPLE_POINT, /*< desc="Sample Point" >*/ GIMP_UNDO_SAMPLE_POINT, /*< desc="Sample Point" >*/
GIMP_UNDO_DRAWABLE, /*< desc="Layer/Channel" >*/ GIMP_UNDO_DRAWABLE, /*< desc="Layer/Channel" >*/
GIMP_UNDO_DRAWABLE_MOD, /*< desc="Layer/Channel modification" >*/ GIMP_UNDO_DRAWABLE_MOD, /*< desc="Layer/Channel modification" >*/
GIMP_UNDO_DRAWABLE_FORMAT, /*< desc="Layer/Channel format" >*/
GIMP_UNDO_MASK, /*< desc="Selection mask" >*/ GIMP_UNDO_MASK, /*< desc="Selection mask" >*/
GIMP_UNDO_ITEM_REORDER, /*< desc="Reorder item" >*/ GIMP_UNDO_ITEM_REORDER, /*< desc="Reorder item" >*/
GIMP_UNDO_ITEM_RENAME, /*< desc="Rename item" >*/ GIMP_UNDO_ITEM_RENAME, /*< desc="Rename item" >*/

View File

@ -1314,6 +1314,55 @@ gimp_drawable_steal_buffer (GimpDrawable *drawable,
g_object_unref (buffer); g_object_unref (buffer);
} }
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);
}
GeglNode * GeglNode *
gimp_drawable_get_source_node (GimpDrawable *drawable) gimp_drawable_get_source_node (GimpDrawable *drawable)
{ {

View File

@ -192,6 +192,11 @@ void gimp_drawable_set_buffer_full (GimpDrawable *drawable,
void gimp_drawable_steal_buffer (GimpDrawable *drawable, void gimp_drawable_steal_buffer (GimpDrawable *drawable,
GimpDrawable *src_drawable); GimpDrawable *src_drawable);
void gimp_drawable_set_format (GimpDrawable *drawable,
const Babl *format,
gboolean copy_buffer,
gboolean push_undo);
GeglNode * gimp_drawable_get_source_node (GimpDrawable *drawable); GeglNode * gimp_drawable_get_source_node (GimpDrawable *drawable);
GeglNode * gimp_drawable_get_mode_node (GimpDrawable *drawable); GeglNode * gimp_drawable_get_mode_node (GimpDrawable *drawable);

View File

@ -0,0 +1,158 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (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
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "core-types.h"
#include "gegl/gimp-gegl-utils.h"
#include "gimp-memsize.h"
#include "gimpimage.h"
#include "gimpdrawable.h"
#include "gimpdrawablepropundo.h"
enum
{
PROP_0
};
static void gimp_drawable_prop_undo_constructed (GObject *object);
static void gimp_drawable_prop_undo_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_drawable_prop_undo_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_drawable_prop_undo_pop (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum);
G_DEFINE_TYPE (GimpDrawablePropUndo, gimp_drawable_prop_undo,
GIMP_TYPE_ITEM_UNDO)
#define parent_class gimp_drawable_prop_undo_parent_class
static void
gimp_drawable_prop_undo_class_init (GimpDrawablePropUndoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass);
object_class->constructed = gimp_drawable_prop_undo_constructed;
object_class->set_property = gimp_drawable_prop_undo_set_property;
object_class->get_property = gimp_drawable_prop_undo_get_property;
undo_class->pop = gimp_drawable_prop_undo_pop;
}
static void
gimp_drawable_prop_undo_init (GimpDrawablePropUndo *undo)
{
}
static void
gimp_drawable_prop_undo_constructed (GObject *object)
{
GimpDrawablePropUndo *drawable_prop_undo = GIMP_DRAWABLE_PROP_UNDO (object);
GimpDrawable *drawable;
G_OBJECT_CLASS (parent_class)->constructed (object);
gimp_assert (GIMP_IS_DRAWABLE (GIMP_ITEM_UNDO (object)->item));
drawable = GIMP_DRAWABLE (GIMP_ITEM_UNDO (object)->item);
switch (GIMP_UNDO (object)->undo_type)
{
case GIMP_UNDO_DRAWABLE_FORMAT:
drawable_prop_undo->format = gimp_drawable_get_format (drawable);
break;
default:
g_return_if_reached ();
}
}
static void
gimp_drawable_prop_undo_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_drawable_prop_undo_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_drawable_prop_undo_pop (GimpUndo *undo,
GimpUndoMode undo_mode,
GimpUndoAccumulator *accum)
{
GimpDrawablePropUndo *drawable_prop_undo = GIMP_DRAWABLE_PROP_UNDO (undo);
GimpDrawable *drawable;
drawable = GIMP_DRAWABLE (GIMP_ITEM_UNDO (undo)->item);
GIMP_UNDO_CLASS (parent_class)->pop (undo, undo_mode, accum);
switch (undo->undo_type)
{
case GIMP_UNDO_DRAWABLE_FORMAT:
{
const Babl *format = gimp_drawable_get_format (drawable);
gimp_drawable_set_format (drawable,
drawable_prop_undo->format,
TRUE, FALSE);
drawable_prop_undo->format = format;
}
break;
default:
g_return_if_reached ();
}
}

View File

@ -0,0 +1,52 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (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
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_DRAWABLE_PROP_UNDO_H__
#define __GIMP_DRAWABLE_PROP_UNDO_H__
#include "gimpitemundo.h"
#define GIMP_TYPE_DRAWABLE_PROP_UNDO (gimp_drawable_prop_undo_get_type ())
#define GIMP_DRAWABLE_PROP_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_DRAWABLE_PROP_UNDO, GimpDrawablePropUndo))
#define GIMP_DRAWABLE_PROP_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_DRAWABLE_PROP_UNDO, GimpDrawablePropUndoClass))
#define GIMP_IS_DRAWABLE_PROP_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_DRAWABLE_PROP_UNDO))
#define GIMP_IS_DRAWABLE_PROP_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_DRAWABLE_PROP_UNDO))
#define GIMP_DRAWABLE_PROP_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_DRAWABLE_PROP_UNDO, GimpDrawablePropUndoClass))
typedef struct _GimpDrawablePropUndo GimpDrawablePropUndo;
typedef struct _GimpDrawablePropUndoClass GimpDrawablePropUndoClass;
struct _GimpDrawablePropUndo
{
GimpItemUndo parent_instance;
const Babl *format;
};
struct _GimpDrawablePropUndoClass
{
GimpItemUndoClass parent_class;
};
GType gimp_drawable_prop_undo_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_DRAWABLE_PROP_UNDO_H__ */

View File

@ -28,6 +28,7 @@
#include "gimpchannelpropundo.h" #include "gimpchannelpropundo.h"
#include "gimpchannelundo.h" #include "gimpchannelundo.h"
#include "gimpdrawablemodundo.h" #include "gimpdrawablemodundo.h"
#include "gimpdrawablepropundo.h"
#include "gimpdrawableundo.h" #include "gimpdrawableundo.h"
#include "gimpfloatingselectionundo.h" #include "gimpfloatingselectionundo.h"
#include "gimpgrid.h" #include "gimpgrid.h"
@ -288,6 +289,22 @@ gimp_image_undo_push_drawable_mod (GimpImage *image,
NULL); NULL);
} }
GimpUndo *
gimp_image_undo_push_drawable_format (GimpImage *image,
const gchar *undo_desc,
GimpDrawable *drawable)
{
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
return gimp_image_undo_push (image, GIMP_TYPE_DRAWABLE_PROP_UNDO,
GIMP_UNDO_DRAWABLE_FORMAT, undo_desc,
GIMP_DIRTY_ITEM | GIMP_DIRTY_DRAWABLE,
"item", drawable,
NULL);
}
/****************/ /****************/
/* Mask Undos */ /* Mask Undos */

View File

@ -72,6 +72,9 @@ GimpUndo * gimp_image_undo_push_drawable_mod (GimpImage *image,
const gchar *undo_desc, const gchar *undo_desc,
GimpDrawable *drawable, GimpDrawable *drawable,
gboolean copy_buffer); gboolean copy_buffer);
GimpUndo * gimp_image_undo_push_drawable_format (GimpImage *image,
const gchar *undo_desc,
GimpDrawable *drawable);
/* mask undos */ /* mask undos */

View File

@ -1807,27 +1807,7 @@ gimp_layer_fix_format_space (GimpLayer *layer,
if (format != gimp_drawable_get_format (drawable)) if (format != gimp_drawable_get_format (drawable))
{ {
GeglBuffer *buffer; gimp_drawable_set_format (drawable, format, copy_buffer, push_undo);
buffer = gegl_buffer_new
(GEGL_RECTANGLE (0, 0,
gimp_item_get_width (GIMP_ITEM (layer)),
gimp_item_get_height (GIMP_ITEM (layer))),
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, push_undo, NULL, buffer);
g_object_unref (buffer);
} }
} }